spring-bean的循环依赖以及解决方式

spring-bean的循环依赖以及解决方式

参考博客: https://blog.csdn.net/u010853261/article/details/77940767

https://blog.csdn.net/qq924862077/article/details/73926268

主要解决方式:使用三级缓存

singletonObjects: 一级缓存, Cache of singleton objects: bean name --> bean instance

earlySingletonObjects: 二级缓存, Cache of early singleton objects: bean name --> bean instance  提前曝光的BEAN缓存

singletonFactories: 三级缓存, Cache of singleton factories: bean name --> ObjectFactory

源码片段如下:

org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean

复制代码
  1 protected <T> T doGetBean(
  2             final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
  3             throws BeansException {
  4 
  5         final String beanName = transformedBeanName(name);
  6         Object bean;
  7 
  8         // Eagerly check singleton cache for manually registered singletons.
  9         Object sharedInstance = getSingleton(beanName);
 10         if (sharedInstance != null && args == null) {
 11             if (logger.isDebugEnabled()) {
 12                 if (isSingletonCurrentlyInCreation(beanName)) {
 13                     logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
 14                             "' that is not fully initialized yet - a consequence of a circular reference");
 15                 }
 16                 else {
 17                     logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
 18                 }
 19             }
 20             bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
 21         }
 22 
 23         else {
 24             // Fail if we're already creating this bean instance:
 25             // We're assumably within a circular reference.
 26             if (isPrototypeCurrentlyInCreation(beanName)) {
 27                 throw new BeanCurrentlyInCreationException(beanName);
 28             }
 29 
 30             // Check if bean definition exists in this factory.
 31             BeanFactory parentBeanFactory = getParentBeanFactory();
 32             if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
 33                 // Not found -> check parent.
 34                 String nameToLookup = originalBeanName(name);
 35                 if (args != null) {
 36                     // Delegation to parent with explicit args.
 37                     return (T) parentBeanFactory.getBean(nameToLookup, args);
 38                 }
 39                 else {
 40                     // No args -> delegate to standard getBean method.
 41                     return parentBeanFactory.getBean(nameToLookup, requiredType);
 42                 }
 43             }
 44 
 45             if (!typeCheckOnly) {
 46                 markBeanAsCreated(beanName);
 47             }
 48 
 49             try {
 50                 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
 51                 checkMergedBeanDefinition(mbd, beanName, args);
 52 
 53                 // Guarantee initialization of beans that the current bean depends on.
 54                 String[] dependsOn = mbd.getDependsOn();
 55                 if (dependsOn != null) {
 56                     for (String dep : dependsOn) {
 57                         if (isDependent(beanName, dep)) {
 58                             throw new BeanCreationException(mbd.getResourceDescription(), beanName,
 59                                     "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
 60                         }
 61                         registerDependentBean(dep, beanName);
 62                         getBean(dep);
 63                     }
 64                 }
 65 
 66                 // Create bean instance.
 67                 if (mbd.isSingleton()) {
 68                     sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
 69                         @Override
 70                         public Object getObject() throws BeansException {
 71                             try {
 72                                 return createBean(beanName, mbd, args);
 73                             }
 74                             catch (BeansException ex) {
 75                                 // Explicitly remove instance from singleton cache: It might have been put there
 76                                 // eagerly by the creation process, to allow for circular reference resolution.
 77                                 // Also remove any beans that received a temporary reference to the bean.
 78                                 destroySingleton(beanName);
 79                                 throw ex;
 80                             }
 81                         }
 82                     });
 83                     bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
 84                 }
 85 
 86                 else if (mbd.isPrototype()) {
 87                     // It's a prototype -> create a new instance.
 88                     Object prototypeInstance = null;
 89                     try {
 90                         beforePrototypeCreation(beanName);
 91                         prototypeInstance = createBean(beanName, mbd, args);
 92                     }
 93                     finally {
 94                         afterPrototypeCreation(beanName);
 95                     }
 96                     bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
 97                 }
 98 
 99                 else {
100                     String scopeName = mbd.getScope();
101                     final Scope scope = this.scopes.get(scopeName);
102                     if (scope == null) {
103                         throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
104                     }
105                     try {
106                         Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
107                             @Override
108                             public Object getObject() throws BeansException {
109                                 beforePrototypeCreation(beanName);
110                                 try {
111                                     return createBean(beanName, mbd, args);
112                                 }
113                                 finally {
114                                     afterPrototypeCreation(beanName);
115                                 }
116                             }
117                         });
118                         bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
119                     }
120                     catch (IllegalStateException ex) {
121                         throw new BeanCreationException(beanName,
122                                 "Scope '" + scopeName + "' is not active for the current thread; consider " +
123                                 "defining a scoped proxy for this bean if you intend to refer to it from a singleton",
124                                 ex);
125                     }
126                 }
127             }
128             catch (BeansException ex) {
129                 cleanupAfterBeanCreationFailure(beanName);
130                 throw ex;
131             }
132         }
133 
134         // Check if required type matches the type of the actual bean instance.
135         if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
136             try {
137                 return getTypeConverter().convertIfNecessary(bean, requiredType);
138             }
139             catch (TypeMismatchException ex) {
140                 if (logger.isDebugEnabled()) {
141                     logger.debug("Failed to convert bean '" + name + "' to required type '" +
142                             ClassUtils.getQualifiedName(requiredType) + "'", ex);
143                 }
144                 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
145             }
146         }
147         return (T) bean;
148     }
复制代码

 总结:简单来说Spring不支持原型bean的循环依赖

原文地址:https://www.cnblogs.com/redcool/p/9870541.html