依赖注入三种方式
- 构造器注入
- set方法注入
- 注解方式注入
循环依赖场景
我们知道spring是通过依赖注入(DI)来完成属性的填充,而循环依赖是指实例化两个bean互相依赖对方的情况,比如A依赖B,B又依赖了A的情况,如图
实例化A时候发现依赖B,从而转去实例化B,在实例化B过程中又发现依赖了A,转去实例化A,如果没有应对策略,spring实例化bean过程就会出现死循环,所以为了解决这个问题,spring是使用了三级缓存,分别为如下所示:
Map<String, Object> singletonObjects
Map<String, Object> earlySingletonObjects
Map<String, ObjectFactory<?>> singletonFactories
这三个Map都是DefaultSingletonBeanRegistry类定义的成员变量,一级缓存singletonObjects存储着所有单例且已经实例化和初始化的bean, 二级缓存存储的是半成品,spring称之为早期对象,三级缓存存储的是实例化工厂方法,负责生产早期对象。
过程分析
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean 为了便于理解,只列出主要代码
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
... 省略部分代码
...
// Create bean instance.
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);
}
}
从创建bean开始,getSingleton(beanName)先尝试从缓存找,看看能不能找到
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
以上这段代码经常被反复调用,是为了看能否从缓存拿到,因为是第一次进来所以肯定还拿不到,也就是返回singletonObject为null;
然后就接着走到
if (mbd.isSingleton())这个分支,进入代码org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton中
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
创建bean之前,beforeSingletonCreation(beanName)将当前bean标志为正在创建中,即添加到集合singletonsCurrentlyInCreation中,
接着singletonObject = singletonFactory.getObject()方法;
这个getObject()方法回到类AbstractBeanFactory的lambda表达式位置,即
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
}
调用createBean(beanName, mbd, args);
接着进入真正实现方法的位置:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean
看到
Object beanInstance = doCreateBean(beanName, mbdToUse, args); 进入此方法
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 省略代码
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
earlySingletonExposure为true,因为上面集合singletonsCurrentlyInCreation已经添加进去,此时三级缓存singletonFactories出场了,key为bean的名称,value为一个lambda表达式,用来生成bean的早期对象(也就是所谓的半成品)。
populateBean(beanName, mbd, instanceWrapper)这里
实现属性填充,完成依赖注入对象的赋值,最终又会回到开始的doGetBean方法,相当于这里是一个递归效果,也就是跟上面一样的流程一样,又走了一遍。
现在假如循环依赖是A依赖B,B又依赖A,那么当创建A发现依赖了B,就会转去创建B,就会再次回到populateBean这里,此时三级缓存中存储了A和B
Ok,接着完成B的属性填充(populateBean)发现依赖了A,所以会转去创建A,还是doGetBean方法,只是有点不太一样,还是这段代码:
Object sharedInstance = getSingleton(beanName);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
1级缓存没有,找二级缓存还是没有,然后从三级缓存找,这时候A是可以找到的,就是上面的lambda表达式,singletonFactory.getObject();
也就是AbstractAutowireCapableBeanFactory的#getEarlyBeanReference
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;
}
此时A被提前生成出来,只不过它还是个半成品(还未完成初始化), 最后将它放到二级缓存earlySingletonObjects中,同时将A从三级缓存中移除,因为B依赖的A有了,接着就可以继续完成后续的初始化工作,B初始化完成后,它就是一个完整的对象,跟着被写入到一级缓存singletonObjects
B完成了初始化后,通过反射赋值给A,接着继续完成A剩余的初始化工作,A完成后续初始化后再也不是半成品了,最后也放到了一级缓存中了。
放入一级缓存的逻辑在类org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton中,也就是回到开始beforeSingletonCreation这个方法中,看到最后finally处
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
删除singletonsCurrentlyInCreation集合,删除二级和三级缓存对应的beanName,写入一级缓存。
简单总结其实就是这样的:
实例化A->放入缓存singletonFactories->填充属性发现依赖B->转去实例化B->放入缓存singletonFactories->填充属性发现依赖A->转去实例化A
->从singletonFactories拿到A半成品->A放入earlySingletonObjects->删缓存singletonFactories的A->赋值给B的属性a,接着完成B的初始化
->B放入singletonObjects->删除缓存singletonFactories的B->赋值给A的属性b->接着继续完成初始化A->放到singletonObjects->删除earlySingletonObjects和singletonFactories中的A.
以上整个过程就是Spring解决循环依赖的处理过程。
疑问
为什么是三级缓存,如果只用一级缓存或者二级缓存行不行?
好,先说一级缓存,这个应该很好解释,肯定不行,为什么?因为如果你把一个半成品放到了缓存中,别的线程来拿,因为缓存中存在,那么就直接拿去用了,这样岂不是GG了。
再谈二级缓存,这里就不得不提AOP代理了,因为有时候我们需要的是代理对象,而不是对象本身,比如很常见的,我们执行某个方法之前先加入一些逻辑,这时候拿到的就一个代理类了,而通过三级缓存singletonFactories来生成早期对象时,有可能就是代理对象,它是通过BeanPostProcessor后处理器做到的,也就是这段代码:
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;
}
org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getEarlyBeanReference
@Override
public Object getEarlyBeanReference(Object bean, String beanName) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
this.earlyProxyReferences.add(cacheKey);
}
return wrapIfNecessary(bean, beanName, cacheKey);
}
wrapIfNecessary完成的工作就是Aop代理,具体实现逻辑大家可以进去看看就知道了。
也就是说二级缓存其实也没问题,只是要把代理对象提前创建出来了,意思就是所有bean创建过程中,不管你有没有循环依赖,如果有需要代理的都给你提前创建了,而不是先放到三级缓存中了,这就违背了spring设计的原则。
Spring 的设计原则是尽可能保证普通对象创建完成之后,再生成其 AOP 代理,也就是尽可能延迟代理对象的生成。
所以 Spring 选择了使用三级缓存,这样既维持了自己定下来的设计原则,又能够解决循环依赖所带来的问题,真是皆大欢喜啊。