序号表示的是学习顺序
IoC(控制反转)/DI(依赖注入):
ioc:思想上是控制反转,spring提供了一个容器,称为IOC容器,用它来充当IOC思想中的外部。
我的理解就是spring把这些对象集中管理,放在容器中,这个容器就叫Ioc这些对象统称为Bean
用对象的时候不用new,直接外部提供(bean)
当外部的对象有关系的时候,IOC给它俩绑好(DI)
DI和IOC组合起来:在容器中建立bean与bean之间的依赖关系的整个过程,因为啥就是比如说
private Dao dao;把它俩对象都装进bean里面(Ioc)然后因为它俩依赖,耦合度太高了,就把它俩关系绑定(DI)。
最终效果:使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系。
IOC入门案例:
1.先在pom.xml中导入spring-context坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
2.创建applicationContext文件
3.在applicationContext文件中配置对应类作为spring管理的bean
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
4.初始化IOC容器,通过容器获取bean
ClassPathXmlApplicationContext()是ApplicationContext的实现类,因为ApplicationContext是一个接口,不能创建对象
这里还涉及类型强转,原本是Object现在变成了 BookService
public class App2 {
public static void main(String[] args) {
//获取IOC容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//获取bean
BookService bookService= (BookService) ctx.getBean("bookService");
bookService.save();
}
}
但是现在还在用new,下面就把new删去
重点就是获取容器,获取bean
DI入门案例:
思路:
1.要删除使用new形式创建的Dao对象
2.然后提供依赖对象对应的setter方法,使需要的Dao对象进入Service中
public void setBookDao(BookDao bookdao){
this.bookDao=bookDao;
}
3.配置service与dao之间的关系,也就是绑定dao与service的关系
property标签中的name指的是BookService中的bookDao属性,ref指的是对应bean的id
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<!-- 配置service与dao的关系-->
<property name="bookDao" ref="bookDao"/>
</bean>
<!-- 2.配置bean-->
<!-- bean标签表示配置bean-->
<!-- id表示给bean起名字-->
<!-- class属性表示给bean定义类型-->
bean的基础配置:
1.基础属性
name:和id差不多,可以给起bean别名,可以用逗号(,)分号(;)空格( )分隔
class:bean的类型或者是说配置bean的全路径类名
<bean id="bookService" name="bookService BOOK" class="com.itheima.service.impl.BookServiceImpl" scope="singleton">
</bean>
注意:如果bean无法通过id或name获取,将无法获取,会抛出异常
NoSuchBeanDefinitionException: No bean named 'bookService1' available
scope:设置bean对象是一个还是多个,默认一个,也就是作用范围
scope="prototype这个是非单例模式,可以创建出多个对象
scope="singleton这个是单例模式,只能创建出一个对象,并且默认就是单例
Bean的实例化(三种):
第一种:构造方法(常用)
java创建对象可以通过直接new和构造方法:
public class Person {
String name;
int age;
// 无参构造方法
public Person() {
this.name = "未知";
this.age = 0;
}
// 带参数的构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
// 使用无参构造方法创建对象
Person person1 = new Person();
// 使用带参数的构造方法创建对象
Person person2 = new Person("张三", 25);
Bean创建对象是使用的无参构造方法:需要提供一个无参的构造方法,所以配置没有任何变化
如果没有提供无参构造方法会抛出异常:
使用无参构造方法创建bean对象例子:
第二种:静态工厂:
首先创建出一个工厂文件夹,然后注意是static静态工厂
这里配置会有变化:
这里的factory-method是工厂里面真正造对象的那个方法
这里的class用于指定工厂类
<bean id="orderDao" factory-method="getBookDao"
class="com.itheima.factory.BookServiceFactory"></bean>
第三种:实例工厂(了解)
配置上有改变:先创建出工厂的对象,还要告诉用工厂里的哪个方法造对象。
第二个bean就没有class了,factory-bean用于指定工厂bean的名称。
<bean id="BookServiceFactory" class="com.itheima.factory.BookServiceFactory"/>
<bean id="BookService" factory-method="getBookDao" factory-bean="BookServiceFactory"/>
Spring改进版(实用):FactoryBean(迷迷糊糊)
配置的时候简单了,不用两步了
<bean id="BookService" class="com.itheima.factory.BookServiceFactoryBean"/>
其它代码:把上面的那个getuserDao变成getObject,就是一直固定了,但是也
Bean生命周期:
配置:
init-method:开始的那个方法
destory-method:结束的那个方法
不能因为你写了一个Public init(){}方法,bean就开始,所以这个init-method是标记的。
<bean id="BookService" class="com.itheima.dao.impl.BookServiceImpl" init-method="init"
destory-method="destory"/>
代码如下:
bean的关闭:
用close方法比较暴力,直接关闭
ctx.registerShutdownHook():这个方法用于向 JVM 注册一个关闭挂钩。当 JVM 关闭时,这个挂钩会被执行。它通常用于执行一些清理操作,比如关闭数据库连接、释放资源等。
public class App {
public static void main(String[] args) {
//3.获取IOC容器
ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerShutdownHook();
BookService bookService= (BookService) ctx.getBean("bookService");
bookService.save();
ctx.close();
}
}
setter注入(构造器注入):
如果是传入非引用类型,比如String,int等
先在相应的类下设置这个变量并且创建出它的setter方法
public class BookServiceImpl implements BookService {
private String chenName;
public void setChenName(String chenName) {
this.chenName = chenName;
}
}
配置上:
主要是第二句
<property name="chenName" value="abcc"></property>
name是属性的名字,value是属性的值
<bean id="bookService" name="bookService" class="com.itheima.service.impl.BookServiceImpl" scope="singleton">
<property name="chenName" value="abcc"></property>
</bean>
以前prooerty经常和ref放在一起,ref属性是用来引用been的,常用于引用类型
构造器注入:
这次就不是用setter方法传,而是用构造方法传
配置上也有变化:用了一个constructor-arg标签