目录
概述
配置文件加载bean(IoC入门)
IoC中设置依赖(DI入门)
Bean的作用范围
Bean的实例化方式
方式一:使用空参构造器(默认)
?方式二:静态工厂
方式三:实例工厂
方式四:Factory Bean(对"实例工厂的优化")
?Bean的生命周期
控制生命周期
关闭IoC容器的方式
?依赖注入的方式
setter方式注入
构造器注入
?依赖自动装配
概述
IoC(Inversion of control) 控制反转,是一种思想。
IoC思想:为了解耦,在程序中不直接new获得对象,而是由外部提供对象(控制反转)。如果我们直接通过new的方式获得对象,需要清楚所有的底层对象初始化过程进行依赖处理,才能进行逻辑处理,而通过IoC引入的对象(外部提供),我们通过依赖注入(DI)的方式进行依赖处理就行。
?spring技术对IoC思想进行了实现。称为 IoC容器
IoC容器从当IoC思想中的"外部",用来负责对象的创建、初始化等一系列工作,在IoC容器中的对象统称为bean。
DI(Dependency Injection)依赖注入:
?在IoC容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。
使用对象不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系。
配置文件加载bean(IoC入门)
测试用的包结构?
1.使用spring-IoC我们需要导入坐标:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
2.创建配置文件,在配置文件中加载bean
?3.在IoC中创建bean
?4.获取IoC中的bean
public class mainTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext();
//通过设置的id获取bean
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
//bean调用方法
userDAO.save();
}
}
IoC中设置依赖(DI入门)
目录结构?
userService中引用UserDAO,并且使用其中的方法。
(使用依赖注入形式,原始是new之后使用new的对象调用其中的方法)
1.引入 依赖
?
?2.设置set方法(相当于是一个入口)
?
?3.到配置文件中设置依赖映射(解决依赖)
<bean id="userServiceImpl" class="com.mh.service.UserServiceImpl">
<!--配置依赖--注意ref,不是value-->
<!--name值要和引入依赖时属性名相同-->
<property name="userDAO" ref="userDAO"></property>
</bean>
<!--依赖加入bean-->
<bean id="userDAO" class="com.mh.dao.UserDAOImpl"></bean>
4.测试方法即可。
Bean的作用范围
?在IoC中定义的bean,默认为单例模式scope:singleton
?设置bean的方式:在<bean> 中添加属性scope
Bean的实例化方式
方式一:使用空参构造器(默认)
在上述案例中均使用此方式构造bean,使用了默认的空参构造器。
?方式二:静态工厂
方式三:实例工厂
跟静态工厂很相似,实例工厂是非静态的,所以需要先将工厂加载到IoC容器中。?
方式四:Factory Bean(对"实例工厂的优化")
?
?Bean的生命周期
提到bean的生命周期,也就是在bean创建时或销毁时做一些事情。
控制生命周期
方式一:使用配置(非标准化)
就是在类中声明两个方法,初始化和销毁的方法,将两个自定义的方法配置到<bean>中。
未控制声明周期时执行
测试代码
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//测试userDAO方法,无依赖,测试成功
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
userDAO.save();
执行结果?
?设置声明周期的控制
在类中声明方法
public class UserDAOImpl implements UserDAO{
@Override
public void save() {
System.out.println("UserDAO...");
}
//自定义初始化和销毁方法
public void init(){
System.out.println("初始化方法加载...");
}
public void destroy(){
System.out.println("销毁方法加载...");
}
}
将方法加载到配置中
?再次测试执行结果:
?会发现一个问题,两个方法,只有初始化方法执行,销毁的方法并没有生效。
方式二:使用接口(标准化)
使用两个接口,实现其中的方法,两个接口分别对应着初始化和销毁的方法。
public class UserDAOImpl implements UserDAO, InitializingBean, DisposableBean {
@Override
public void save() {
System.out.println("UserDAO...");
}
//销毁方法
@Override
public void destroy() throws Exception {
}
//初始化方法(在属性之后执行)
@Override
public void afterPropertiesSet() throws Exception {
}
}
执行测试方法,和方式一 一样:
?两种方法可以看出,只有初始化方法执行,销毁的方法没有被执行,也就是声明周期并没有在虚拟机关闭前自动的调用销毁方法,所以我们只能手动将IoC容器关闭,才会执行销毁方法。
关闭IoC容器的方式
1.手动关闭容器
具体使用:close()
测试代码
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//测试userDAO方法,无依赖,测试成功
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
userDAO.save();
//手动关闭容器
context.close();
测试代码执行结果(销毁方法执行)
2.注册钩子?
测试代码?
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDAO userDAO = (UserDAO) context.getBean("userDAO");
userDAO.save();
context.registerShutdownHook();
?测试代码执行结果和手动关闭结果一致
手动关闭和注册钩子的方式说明:手动关闭需要考虑书写的位置,一般写到代码最后,而注册钩子则没有书写位置要求。
?依赖注入的方式
setter方式注入
引用数据类型?
setter注入,就是给需要的依赖设置set方法,包括基本数据类型和引用数据类型。
依赖:userDAO ,设置set方法
public class UserServiceImpl implements UserService{
//引用数据类型
private UserDAO userDAO;
//设置set方法
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
@Override
public void save() {
//在其中调用userDAO(依赖)
userDAO.save();
System.out.println("userService...");
}
}
?配置依赖
<bean id="userDAO" class="com.mh.dao.UserDAOImpl"></bean>
<bean id="userServiceImpl" class="com.mh.service.UserServiceImpl">
<property name="userDAO" ref="userDAO"></property>
</bean>
简单数据类型
?设置简单数据类型依赖,并且设置set方法
public class UserDAOImpl implements UserDAO {
//设置简单数据类型依赖
private String uname;
//设置set方法
public void setUname(String uname) {
this.uname = uname;
}
@Override
public void save() {
System.out.println("UserDAO..." + uname);
}
}
配置依赖
<bean id="userDAO" class="com.mh.dao.UserDAOImpl">
<!--使用value属性赋值-->
<property name="uname" value="Tom"/>
</bean>
构造器注入
类中设置简单数据类型和构造器
public class GoodsDAOImpl implements GoodsDAO {
int num;
public GoodsDAOImpl(int num){
this.num = num;
}
@Override
public void save() {
System.out.println("goods..." + num );
}
}
<bean id="goodsDAO" class="com.mh.dao.GoodsDAOImpl">
<constructor-arg name="num" value="100"/>
</bean>
类型装配
此方式存在紧耦合(属性名字需要一致),不利于使用。解决方式:使用类型进行装配
<bean id="goodsDAO" class="com.mh.dao.GoodsDAOImpl">
<constructor-arg type="int" value="100"/>
</bean>
此方式解决了名字的耦合问题,但是存在:万一数据类型不唯一的情况就不可用。
比如存在两个int类型的情况。这种情况下:就可以使用索引进行装配。
索引装配
<bean id="goodsDAO" class="com.mh.dao.GoodsDAOImpl">
<constructor-arg index="0" value="100"/>
</bean>
依赖注入的方式选择?
?依赖自动装配
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
?自动装配的方式:
1.按类型装配
2.按名称装配
?自动装配特征
- 自动装配用于引用类型依赖注入,不能简单类型进行操作。
- 使用按类型装配时,必须保障容器中相容类型的bean唯一。
- 使用按名称装配时,必须保障容器中具有指定名称的bean。
- 自动装配优先级低于setter注入与构造器注入。两者使用可能会发生冲突导致报错。
|