一、Spring Bean生命周期简介
Spring Bean的生命周期是从Bean实例化之后,即通过反射创建出对象,到Bean成为一个完整对象,最终存储到单例池中,这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为3个阶段:
- Bean的实例化阶段:Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是singleton的,是否是延迟加载的,是否是FactoryBean等,最终将一个普通的singleton的Bean通过反射进行实例化;
- Bean的初始化阶段:Bean创建后还仅仅是一个半成品,还需要对Bean实例的属性进行填充、执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义的初始化init方法等,该阶段是Spring最具有技术含量和复杂度的阶段,Aop增强功能、Spring的注解功能、Bean的循环引用问题等都是在这个阶段体现的;
- Bean的完成阶段:经过初始化阶段,Bean就成为一个完整的Spring Bean,被存储到单例池SingletonObjects中,即完成了一个完成的Spring Bean周期。
其中Bean的初始化阶段是Spring Bean的生命周期中比较复杂和重要的部分,涉及如下几个过程:
- Bean实例的属性填充;
分为如下几种情况:
- 注入普通属性,String、int或者存储基本类型的集合时,直接通过set方法的反射设置属性值;
- 注入单向对象引用属性时,从容器中getBean获取后通过set方法的反射设置属性,如果容器中没有(由于容器管理对象不分先后,所以需要的对象属性可能还没有实例化),则先暂停初始化,去创建被注入对象Bean实例(完成整个生命周期)后,在反过来开始初始化,将需要设置的对象属性赋值;
- 注入双向对象引用属性,涉及循环引用(循环依赖)问题,比较复杂,这里不做描述,下面的 Spring Bean生命周期中的循环依赖问题 会作详细介绍(通过三级缓存解决循环引用)
- Aware接口的属性注入;
- BeanPostProcessor的Before()方法回调;
- InitializingBean接口的初始化方法回调;
- 自定义初始化init方法的回调;
- BeanPostProcessor的after()方法回调;
二、Spring Bean生命周期中的循环依赖问题
1.循环依赖
在Java中,循环依赖通常发生在依赖注入的场景中,指的是两个或多个bean相互依赖对方,形成了一个循环,导致容器无法正确解析和初始化这些bean。如下代码:
@Component
public class BeanA {
@Autowired
private BeanB beanB;
// ...
}
@Component
public class BeanB {
@Autowired
private BeanA beanA;
// ...
}
在这个例子中,BeanA
依赖 BeanB
,而 BeanB
又依赖 BeanA
,这就形成了一个循环依赖。
2.解决循环依赖
Spring框架通过三级缓存帮助解决循环依赖,如下是关于三级缓存的代码:
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);
}
解决循环依赖的过程:
public class UserServiceImpl implements UserService {
private UserDaoImpl userDao;
public void setUserDao(UserDaoImpl userDao) {
this.userDao = userDao;
}
}
public class UserDaoImpl implements UserDao {
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
}
1.userService实例化对象,但尚未初始化,未被其他对象引用,将userService存储到三级缓存
2.userService属性注入,需要userDao,从上述缓存中获取,此时缓存中没有userDao
3.userDao实例化对象,但尚未初始化,未被其他对象引用,将userDao存储到三级缓存
4.userDao属性注入,需要userService,从三级缓存中可以获取userService,此时userService被userDao引用,将userService从三级缓存移入到二级缓存(三级缓存已经没有userService)
5.userDao执行其他生命周期过程,最终初始化为完整的Bean对象,将userDao存储到一级缓存,并将userDao从二三级缓存删除(其实是从三级缓存删除,二级缓存并没有)
6.回到userService属性注入,此时UserDao在一级缓存中已经存在,直接注入UserDao
7.userService执行其他生命周期过程,最终初始化为完整的Bean对象,将userService存储到一级缓存,并将userService从二三级缓存删除(其实是从二级缓存删除,三级缓存并没有)