spring源码阅读2: 循环依赖1
在上一篇文章中,我们分析了@Autowired 的主要注入过程。这一篇我们分析一下spring 是如何通过缓存解决spring 循环依赖的。在分析前先阐述一下本文中用到的两个词语的意思:
- 实例化
这里的实例化是指通过构造器创建出对象,也就是执行了源码一中的createBeanInstance方法。 - 初始化
这里的初始化时指执行了源码一种的populateBean和initializeBean方法。populateBean方法会处理@Autowired,@value注入、setter注入等。而initializeBean会处理Aware回调,例如ApplicationContextAware,自定义的初始化方法、InitializingBean回调等等。
什么是spring 循环依赖
假设有两个spring bean 如下:
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
public class ServiceB {
@Autowired
private ServiceB serviceB;
}
假设是Service A 先创建,那么大概的创建流程如下:
- 通过无参构造器实例化出serviceA对象
- 处理serviceA的@Autowired,发现要注入ServiceB
- 去spring 容器中查找ServiceB对象
- 发现ServiceB 还没有创建
- 通过无参构造器实例化一个ServiceB对象
- 处理ServiceB的@Autowired,发现要注入serviceA
- 去spring 容器中查找ServiceA对象
- 发现ServiceA还没有创建,去创建ServiceA对象
从上面流程可以看出,如果不进行特殊的处理,就会陷入要创建ServiceA就要先创建ServiceB,要创建ServiceB就要先创建ServiceA的循环中。spring为了解决这种循环依赖的问题,在spring bean 创建的过程中增加了缓存。也就是在上面流程的第一步和第二步之间增加一步:先将实例化后的ServiceA对象保存到缓存中,那么当进行到第8步的时候,如果发现Service A还没初始化完成,就先从缓存中取出ServiceA的对象注入。具体流程见下面的源码分析
源码分析
源码一:AbstractAutowireCapableBeanFactory.doCreateBean()
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 返回spring bean实例,如果没有指定构造器或者工厂方法,通常就是简单的通过无参构造器返回一个对象。注意这时候返回的对象,所有的字段都还是默认值
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 这里返回来的就是实例化的spring bean
Object bean = instanceWrapper.getWrappedInstance();
// 省略部分代码
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 当允许循环依赖的时候,先将实例化的spring bean保存到缓存中,详情见源码2、源码3
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
// 会在这一步调用AutowiredAnnotationBeanPostProcessor的postProcessProperties方法,处理@Autowire、@value等注入
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 省略部分代码
return exposedObject;
}
源码二:DefaultSingletonBeanRegistry.addSingletonFactory()
// 缓存的初始化完成后的spring bean对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 缓存对象对应的对象工厂,可以通过ObjectFactory.getObject()到对象
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 缓存的早期的单例对象也就是刚刚实例化完成的对象
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// 根据单例对象注册的顺序保存单例对象的beanName
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
// 如果singletonObjects没有包含对应的bean说明该bean还没有初始化完成。
if (!this.singletonObjects.containsKey(beanName)) {
// 保存beanName对应的ObjectFactory,ObjectFactory是一个函数接口,提供了一个getObject()方法,返回对象,结合源码三,可以知道就是返回刚刚实例化完成的对象;
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
源码三、AbstractAutowireCapableBeanFactory.getEarlyBeanReference()
// 通常而言,这个方法会之间返回传入的bean,在本文中也就是会返回刚刚实例化完成的bean对象,但是某些情况下可能会返回动态代理后的对象,例如当bean中存在@Transactional的时候,下篇文章会阐述这个问题
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
}
}
}
return exposedObject;
}
上面分析了spring 缓存实例化后的spring bean的流程,下面我们通过分析依赖查找的源码,分析是如何获取这些缓存的对象的。
源码四:AbstractBeanFactory.doGetBean()
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
// 查询是否有缓存的单例对象,详情见源码5
Object sharedInstance = getSingleton(beanName);
// 如果缓存中已经存在对象,那么进行一些判断处理后返回
if (sharedInstance != null && args == null) {
// 省略部分代码
}
else {
// 省略部分代码
try {
// 省略部分代码
// 如果缓存中没有单例对象就先去创建对象(见源码一),然后将对象保存在缓存中(见源码6)
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 省略部分代码
return (T) bean;
}
源码五:DefaultSingletonBeanRegistry.getSingleton()
// 缓存的初始化完成后的spring bean对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 缓存对象对应的对象工厂,可以通过ObjectFactory.getObject()到对象
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 缓存的早期的单例对象也就是刚刚实例化的对象
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
// 根据单例对象注册的顺序保存单例对象的beanName
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 先从singletonObjects中查询是否有初始化完成后的bean对象
Object singletonObject = this.singletonObjects.get(beanName);
// 如果没有初始化完成后的对象,同时对象正在创建中,则进入下面的流程
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//如果允许循环依赖,那么就从singletonFactories中获取对象的ObjectFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 调用ObjectFactory.getObject()方法,获取到缓存的早期引用对象也就是刚刚实例化的对象
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
源码六:DefaultSingletonBeanRegistry.getSingleton()
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
// 省略部分代码
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
// 省略部分代码
if (newSingleton) {
// 将调用createBean()方法返回的对象(初始化完成后的对象)保存到singletonObjects中,
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
总结
在分析完源码后,我们重新调整一下ServiceA和ServiceB的流程
- 通过无参构造器实例化出serviceA对象
- 将实例化的ServiceA对象保存到缓存singletonFactories中
- 处理serviceA的@Autowired,发现要注入ServiceB
- 去spring 容器中查找ServiceB对象
- 发现ServiceB 还没有创建
- 通过无参构造器实例化一个ServiceB对象
- 处理ServiceB的@Autowired,发现要注入serviceA
- 去spring 容器中查找ServiceA对象
- 从singletonFactories中获取实例化的ServiceA对象,完成ServiceB的创建
- 完成ServiceB的创建后,就可以继续ServiceA对象的初始化
上面的流程就是spring 解决普通spring bean 循环依赖的的总体流程。但是对应一些需要动态代理的spring bean ,例如带有@Async注解的spring bean,我们常常会遇到 一个 BeanCurrentlyInCreationException 异常,然后类型下面的报文,下一篇文章我们分析这个异常产生的原因。
in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.