spring循环依赖策略解析
循环依赖 所谓循环依赖就是多个Bean之间依赖关系形成一个闭环,例如A->B->C->...->A 这种情况,当然,最简单的循环依赖就是2个Bean之间互相依赖:A->B(A依赖B),B->A(B依赖A) 。在Spring中,如果A->B,那么在创建A的过程中会去创建B,在创建B(或B的依赖)的过程中又发现B->A,这个时候就出现了循环依赖的现象。 循环依赖的解决 spring中的循环依赖只有当 1.Bean是单例, 这两个条件满足的情况下是没问题的。但是如果是通过构造器依赖,或者不是单例模式的情况下循环依赖就会抛出异常BeanCurrentlyInCreationException。下面从代码层面上解析一下为什么。 Prototype的循环依赖问题 为什么最先介绍Prototype的循环依赖呢,因为可以顺便介绍在Spring中创建Bean的流程核心流程:在AbstractFoctory的doGetBean的方法。这个方法很长,这里只写出核心逻辑,并在注解上注明了个人理解: 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; //尝试获取单例对象,因为spring大部分的bean都是单例的,所以这里先尝试能否获取。 registered singletons. Object sharedInstance = getSingleton(beanName); //单例存在的情况下,那么beanName返回的肯定是单例类,但是这里还需要判断是不是FactoryBean if (sharedInstance != null && args == null) { ... //FactoryBean应该返回getObject()对象 bean = getObjectForBeanInstance(sharedInstance,name,beanName,null); } else { //走到这里,有可能beanName是单例模式,但之前并没有实例化,或者是Prototype类型。 //首先判断不是循环依赖,这里的循环依赖指的是Prototype类型 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } try { final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // 如果是单例,则创建单例模式 if (mbd.isSingleton()) { // !!!这里是解决单例循环依赖的关键,后面再分析 sharedInstance = getSingleton(beanName,new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { return createBean(beanName,mbd,args); } catch (BeansException ex) { throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance,mbd); } else if (mbd.isPrototype()) { // 原型模式,则创建一个新对象. Object prototypeInstance = null; try { /*这里是Prototype循环依赖的问题,会记录在map中beanName, 如果在解决当前Bean的依赖过程中还依赖当前Bean, 则说明了出现了循环依赖 */ beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName,args); } finally { //对应beforePrototypeCreation(),从map中移除 afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance,mbd); } ... } } ... return (T) bean; } 可以看出,该流程中就考虑了Prototype的循环依赖的问题,只要在创建Prototype的Bean中出现循环依赖那么就抛出异常。但是在singleton的情况下,则通过另外的方式来解决。 Singleton的循环依赖之构造注入 在上面介绍中,出现了一个很关键的地方: sharedInstance = getSingleton(beanName,new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { return createBean(beanName,args); } catch (BeansException ex) { throw ex; } } }); 这个getSingleton涉及到了ObjectFactory这个接口类,这个接口的功能和FactoryBean类似,但是主要是用来解决循环依赖的。在初始化过程同决定返回的Singleton对象是。关于单例的对象的创建,又要介绍一下DefaultSingletonBeanRegistry这个类,这个类主要用来帮助创建单例模式,其中主要的属性: /** 缓存创建的单例对象: bean名字 --> bean对象 */ private final Map<String,Object> singletonObjects = new ConcurrentHashMap<String,Object>(256); /** 缓存单例的factory,就是ObjectFactory这个东西,: bean name --> ObjectFactory */ private final Map<String,ObjectFactory<?>> singletonFactories = new HashMap<String,ObjectFactory<?>>(16); /** 也是缓存创建的单例对象,功能和singletonObjects不一样, 在bean构造成功之后,属性初始化之前会把对象放入到这里, 主要是用于解决属性注入的循环引用: bean name --> bean instance */ private final Map<String,Object> earlySingletonObjects = new HashMap<String,Object>(16); /** 记录在创建单例对象中循环依赖的问题,还记得Prototype中又记录创建过程中依赖的map吗? 在Prototype中只要出现了循环依赖就抛出异常,而在单例中会尝试解决 */ private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<String,Boolean>(16)); 现在回过来看getSingleton(beanName,new ObjectFactory<Object>()这个方法的实现。 public Object getSingleton(String beanName,ObjectFactory<?> singletonFactory) { synchronized (this.singletonObjects) { //尝试在singletonObjects中获取 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { //不存在则创建 //把当前beanName加入到singletonsCurrentlyInCreation中 beforeSingletonCreation(beanName); try { singletonObject = singletonFactory.getObject(); } ... finally { ... //从singletonsCurrentlyInCreation中删除beanName afterSingletonCreation(beanName); } } return (singletonObject != NULL_OBJECT ? singletonObject : null); } } 这段逻辑是不是和Prototype中解决循环类似,这里其实就是调用了ObjectFactory的getObject()获取对象,回过头去看前面代码,ObjectFactory的getObject()方法实际调用的是createBean(beanName,args)。说到createBean(beanName,args)又不得不说AbstractAutowireCapableBeanFactory这个类,主要功能就是完成依赖注入的Bean的创建,这个类的createBean方法代码如下,注意注解说明: @Override protected Object createBean(String beanName,RootBeanDefinition mbd,Object[] args) throws BeanCreationException { ... Object beanInstance = doCreateBean(beanName,mbdToUse,args); ... } protected Object doCreateBean(final String beanName,final RootBeanDefinition mbd,final Object[] args) throws BeanCreationException { // 实例化bean BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //如果没实例化则创建新的BeanWrapper //如果是通过构造器注入,这里是一个关键点 /* 因为在A初始化的时候发现构造函数依赖B,就会去实例化B, 然后B也会运行到这段逻辑,构造函数中发现依赖A, 这个时候就会抛出循环依赖的异常 */ instanceWrapper = createBeanInstance(beanName,args); } //如果当前是单例,并且allowCircularReferences为true(默认就是true,除非我们不希望Spring帮我们解决) boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { /* !!!这里很重要,把构造成功,但属性还没注入的 的bean加到singletonFactory中,这样再解决A的依赖 过程中如果依赖A,就把这个半成品返回回去。 */ addSingletonFactory(beanName,new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName,bean); } }); } Object exposedObject = bean; try { //自动注入属性 populateBean(beanName,instanceWrapper); if (exposedObject != null) { exposedObject = initializeBean(beanName,exposedObject,mbd); } } ... return exposedObject; } 注解已经注明了我的理解。就不再赘述 总结 上面代码是我一边debug一个写下的,现在写完了,根据自己的理解总结一下。 相关类说明 AbstractBeanFactory,这个类中包含了Bean创建的主要流程,在doGetBean这个方法中包含了对Prototype循环依赖处理。逻辑很简单,出现了循环依赖则直接抛出异常 DefaultSingletonBeanRegister 用于管理Singleton的对象的创建,以及解决循环依赖的问题,其中解决循环依赖的关键属性就是了earlySingletonObjects,他会在构造Singleton对象过程中暂时缓存构造成功,但属性还未注入的对象,这样就可以解决循环依赖的问题。 AbstractAutowireCapableBeanFactory,自动注入的相关逻辑,包自动注入的对象的创建、初始化和注入。但如果在调用构造函数中发现了循环依赖,则抛出异常 ObjectFactory,这个接口功能和FactoryBean类似,但是为了解决循环依赖,他决定了在获取的getSingleton()是一个完成品还是一个半成品。 思考 如果A--构造依赖->B,B--属性依赖-->A,例如: @Component public class BeanA { private BeanB beanB; @Autowired public BeanA(BeanB beanB) { this.beanB = beanB; } } @Component public class BeanB { @Autowired private BeanA beanA; } 这种情况会异常吗?提示:都有可能 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |