七、Spring Bean 的生命周期
Spring Bean 的生命周期是从Bean的实例化之后(通过反射创建出对象之后),到Bean成为一个完整的对象,最终存储到单例池之中,这个过程被称为Bean的生命周期。Spring Bean的生命周期大致分为三个阶段:
- Bean实例化阶段:
- Spring框架会取出BeanDefinition信息进行判断当前Bean的范围是否是singleton,是否延迟记载…最终将singleton的Bean通过反射实例化;
- Bean初始化阶段:
- Bean创建之后(是个半成品),还要对其属性进行填充,执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法,执行自定义init方法等。涉及到Aop增强,Spring注解,Bean循环引用等问题。
- Bean的完成阶段:
- 初始化后的Bean是一个完整的Spring Bean,存储在singletonObjects,这就完成了整个生命周期。
7.1 Bean初始化阶段
涉及到以下几个阶段:
- Bean实例的属性填充;
- Aware接口属性注入;
- BeanPostProcessor的before()方法回调;
- InitializingBean接口的初始化方法回调;
- 自定义初始化方法回调;
- BeanPostProcessor的after()方法回调;
7.1.1 Bean实例的属性填充
BeanDefinition中对当前Bean实体的注入信息通过属性propertyValues进行存储;
Spring 进行属性填充时,有以下几种情况:
- 对String,int等基本属性注入,直接通过set方法的反射设置;
- 对单向对象引用属性注入,从容器中getBean的方式获取后set方法反射设置;如果容器中没有,则先创建被注入对象的实例(整个生命周期后,及属性注入等操作完成),再注入;
- 双向对象属性的引用,会涉及到循环依赖(循环引用)的问题;
循环依赖:多个实体间相互依赖并形成闭环的情况;如BeanA依赖于BeanB,BeanB依赖于BeanA。
public class DUserServiceImpl implements DUserService {
public void setUserDao(DUserDao userDao) { }
}
public class DUserDaoImpl implements DUserDao {
public void setUserService(DUserService userService) { }
}
<bean id="dUserService" class="xxx.DUserServiceImpl">
<property name="userDao" ref="dUserDao"></property>
</bean>
<bean id="dUserDao" class="xxx.DUserDaoImpl">
<property name="userService" ref="dUserServce"></property>
</bean>
解决循环依赖的方案:三级缓存
Spring 提供三级缓存存储完整的Bean和半成品的Bean,用来解决循环依赖。
在DefaultListableBeanFactory的父类DefaultSingletonBeanRegistry中的方法:
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
// 最终存储单例完整Bean的容器,这里的Bean实例化和初始化都完成,称为 一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
// 早期Bean单例池,缓存半成品的Bean,且当前对象被其他对象引用,称为 二级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
// 单例Bean的工厂池,缓存半成品的Bean,当前对象未被引用,使用时通过工厂创建Bean,称为 三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
UserService和UserDao循环依赖结合三级缓存的过程:
- UserService实例化对象,尚未初始化,将实例化后的UserService存储到三级缓存;
- UserService属性注入,需要引用UserDao,从缓存中获取,没有UserDao;需要实例化UserDao;
- UserDao实例化对象尚未初始化,将实例化后的UserDao存储到三级缓存;
- UserDao属性注入,需要引用UserService,从三级缓存中获取,有UserService;UserService从三级缓存移到二级缓存;
- UserDao继续执行其他生命周期过程,最终成为一个完成的Bean,存到一级缓存,删除二三级缓存;
- UserService注入UserDao;
- UserService继续执行其他生命周期过程,最终成为一个完成的Bean,存到一级缓存,删除二三级缓存;
图解如下: