spring6-bean的生命周期与循环依赖
bean的生命周期
粗略划分5步
- 实例化bean
调用的是无参数的构造方法
- bean属性赋值
执行set注入
- 初始化bean
调用bean的init()方法,需要自己写,自己配
-
使用bean
-
销毁bean
调用bean的destroy(),需要自己写,自己配
注意:自定义的init()和destroy()需要在配置文件配置
<!-- init-method指定初始化方法,destroy-method指定销毁方法-->
<!-- 这两个方法需要在bean类中定义-->
<bean id="user" class="com.ali.bean.User" init-method="initBean" destroy-method="destroyBean"></bean>
进一步七步
在以上的5步中,第三步是初始化bean。其实可以在初始化之前和初始化之后添加代码。此时,需要加入“Bean后处理器”。
编写一个类实现BeanPostProcessor类,并重写before和after方法
- 实例化bean
调用的是无参数的构造方法
- bean属性赋值
执行set注入
- 执行“Bean后处理器”的before方法
- 初始化bean
调用bean的init()方法,需要自己写,自己配
-
执行“Bean后处理器”的after方法
-
使用bean
-
销毁bean

// 日志类bean后处理器
public class LogBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor befor方法");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("BeanPostProcessor after方法");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
<!-- 配置bean后处理器
这个bean后处理器会在bean实例化后和初始化前后执行相应的方法
例如可以在bean初始化前后打印日志
需要实现BeanPostProcessor接口
这样spring容器在创建其他bean时会自动调用这个后处理器的相应方法
例如上面的springBean在实例化和初始化时就会调用LogBeanPostProcessor中的方法
这样就可以在控制台看到日志输出
这个bean后处理器必须配置在spring配置文件中,才能被spring容器识别和调用
这个bean后处理器将作用于当前配置文件中的所有bean
-->
<bean class="com.ali.bean.LogBeanPostProcessor" />
精细化分为10步
- 实例化bean
调用的是无参数的构造方法
- bean属性赋值
执行set注入
-
检查bean是否实现Aware相关接口(BeanNameAware, BeanClassLoaderAware, BeanFactoryAware),如果实现了,则调用这些接口相关的方法。
-
执行“Bean后处理器”的before方法
-
检查bean是否实现InitializingBean接口,并调用接口方法
-
初始化bean
调用bean的init()方法,需要自己写,自己配
-
执行“Bean后处理器”的after方法
-
使用bean
-
检查bean是否实现了DisposableBean接口,并调用接口方法
-
销毁bean
调用bean的destroy(),需要自己写,自己配
spring容器只对singleton的bean进行完整的生命周期管理。
如果是prototype作用域的bean,spring容器只负责初始化完毕,等客户端程序一旦获取到该bean后,spring容器就不再管理该对象的声明周期了。
自己new的对象如何让spring容器管理
使用DefaultListableBeanFactory类注入自己创建的对象。
public static void main(String[] args) {
User user = new User();
System.out.println(user);
// 将以上new的对象交给spring容器管理
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerSingleton("userBean", user);
// 从spring容器中获取
Object userBean = beanFactory.getBean("userBean");
System.out.println(userBean);
}
bean的循环依赖问题
bean的循环依赖:A对象中有B属性。B对象中有A属性。这种你依赖我,我依赖你的情况就是循环依赖。
singleton+setter模式
<!-- singleton+setter方式解决循环依赖-->
<!-- 通过setter方法注入依赖,可以解决循环依赖问题 -->
<!-- spring容器在创建bean时会先实例化bean对象,然后通过setter方法注入依赖-->
<!-- 这样即使存在循环依赖,spring也能正确创建和注入bean-->
<bean id="husbandBean" class="com.ali.bean.Husband" >
<property name="name" value="Jack"/>
<property name="wife" ref="wifeBean"/>
</bean>
<bean id="wifeBean" class="com.ali.bean.Wife" >
<property name="name" value="Rose"/>
<property name="husband" ref="husbandBean"/>
</bean>
在这种模式(singleton+setter)下主要分为2个阶段来解决:
1. 在spring容器加载的时候,实例化bean。只要其中任意一个bean实例化之后,马上进行“曝光”【不等属性赋值就曝光】
2. bean“曝光”后再进行赋值
prototype+setter模式
<!-- 在prototype+setter方式下无法解决循环依赖问题,会出现异常
因为prototype作用域下,spring容器不会缓存bean实例,每次获取都会创建一个新的实例
这样当husbandBean实例化时,wifeBean还没有被创建,导致无法注入wifeBean
反之亦然,最终会导致循环依赖失败,抛出异常
所以prototype作用域下不支持循环依赖
但是:当2个bean的scope不同时(其中任意一个是singleton)是可以的
例如下面的配置中,husbandBean是singleton作用域,wifeBean是prototype作用域
这样在创建husbandBean时,wifeBean会被创建并注入
但是每次获取wifeBean时,都会创建一个新的实例
这样就避免了循环依赖的问题
因为singleton只会创建一次,而prototype每次获取都会创建新的实例
所以这种组合方式是可行的-->
<bean id="husbandBean" class="com.ali.bean.Husband" scope="singleton">
<property name="name" value="Jack"/>
<property name="wife" ref="wifeBean"/>
</bean>
<bean id="wifeBean" class="com.ali.bean.Wife" scope="prototype">
<property name="name" value="Rose"/>
<property name="husband" ref="husbandBean"/>
</bean>
本文来自博客园,作者:NE_STOP,转载请注明原文链接:https://www.cnblogs.com/alineverstop/p/19571999
浙公网安备 33010602011771号