问:何为循环依赖
A类中引用B类, B类中引用A类。此情况下为循环引用
问:如何解决
需要从bean的创建过程说起。
spring在容器启动过程中,开始创建A,在createBean过程中。会尝试从缓存中
/**只截取部分代码*/
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
// 尝试从缓存中获取实例对象
Object sharedInstance = getSingleton(beanName);
.....
}
getSingleton方法只是从singletonObjects、earlySingletonObjects、singletonFactories中一层一层获取
//存放创建完好的bean实例
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** bean对应的ObjectFactory, ObjectFactory只是一个接口,用于创建早期引用
*/
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/**存放早期引用*/
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
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 != NULL_OBJECT ? singletonObject : null);
}
如果A类没有从缓存中获取,bean创建过程正常往下执行,执行过程中会存在下面代码
//是否允许早期暴露
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//允许的话将该类对应的ObjecFactory放入singletonFactories中
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
至此A类的ObjectFactory已放入缓存中,但此时还未对A进行属性注入和执行初始化方法。在属性注入时,A类引入B类,会先创建B类,在执行过程中,B类进行属性注入时获取A类的方法便是通过A类的ObjectFactory获取A的早期引用完成B类的创建,然后再完成A类的创建。
总结
spring解决循环依赖的方法是通过三级缓存去解决的,通过生成类的早期引用(不完整的bean,相当于只是完成new操作,未进行属性注入和执行初始化方法),完成bean的创建
为何要三级缓存,二级缓存可以解决不?
二级缓存本身可以解决循环依赖,三级缓存只是为了在发生循环依赖的情况时,如果A的创建涉及到了代理,会提前给A类生成代理。(正常生成代理的时机是再A执行初始化方法后,会执行后置处理器的后置方法中创建。三级代理改变了创建代理的时机)