• 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的循环依赖

  • 相关阅读:
    [eslintpluginvue] [vue/nounusedvars] 'scope' is defined but never used.
    Vue项目中添加锁屏功能
    前端文档汇总(含代码规范、开发流程、知识分享,持续更新)
    vscode格式化Vue出现的问题
    下盘不稳 被忽视的项目风险
    项目沟通中的一点经验心得
    如何才能更合理地分配项目奖金?
    关于企业的薪酬体系之思考
    导致项目失败的两大隐形杀手
    如何让项目总结会议更有效果?
  • 原文地址:https://www.cnblogs.com/redcool/p/9870541.html
Copyright © 2020-2023  润新知