<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          深入源碼剖析 springboot bean的循環(huán)依賴

          共 27105字,需瀏覽 55分鐘

           ·

          2021-07-05 13:54

          點擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”

          優(yōu)質(zhì)文章,第一時間送達(dá)

            作者 |  wang03

          來源 |  urlify.cn/bMjuEz

          本文基于springboot版本2.5.1

              <parent>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-parent</artifactId>
                  <version>2.5.1</version>
                  <relativePath/> <!-- lookup parent from repository -->
              </parent>

          本文主要聚焦在循環(huán)依賴部分,主要用單例bean來進(jìn)行講解,其他bean實現(xiàn)的流程不會過多涉及。

          1、什么叫循環(huán)依賴呢

          簡單來說就是springboot容器中的多個bean,如A、B兩個bean,A有屬性B需要注入,B有屬性A需要注入,形成相互依賴的情況。

          看下代碼,就是類似下面這種情況

          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.stereotype.Component;

          @Component
          public class ServiceA {
              @Autowired
              private ServiceB serviceB;
          }
          import org.springframework.beans.factory.annotation.Autowired;
          import org.springframework.stereotype.Component;

          @Component
          public class ServiceB {
              @Autowired
              private ServiceA serviceA;
          }

          上面有兩個bean,分別是ServiceA,ServiceB。ServiceA中需要注入ServiceB的實例,ServiceB中需要注入ServiceA的實例,這就是一種典型的循環(huán)依賴,其他還有方法參數(shù)循環(huán)依賴的場景等等,但是它們的內(nèi)部實現(xiàn)基本是一樣的。

          2、具體出現(xiàn)循環(huán)依賴的代碼邏輯

          (1)獲取bean的方法

          在springboot中默認(rèn)的beanFactory是DefaultListableBeanFactory,在我們獲取bean對象的時候,如果bean對象存在就直接返回,如果不存在,就先創(chuàng)建bean對象再返回。

          我們先看下我們獲取bean的常用方法都有哪些

          public <T> T getBean(Class<T> requiredType) throws BeansException
          public Object getBean(String name) throws BeansException
          public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException
          public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)
          public void preInstantiateSingletons() throws BeansException 

          常用的獲取bean的方法主要有上面幾個和它們的重載版本,對于第3行、第4行、第5行最終都會調(diào)用到第2行的方法來獲取bean。而它也會通過調(diào)用doGetBean(在AbstractBeanFactory這個類中)來獲取bean

           public Object getBean(String name) throws BeansException {
            return doGetBean(name, null, null, false);
           }

          第1行的方法也會調(diào)用doGetBean來獲取bean

           public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
             throws BeansException {

            return doGetBean(name, requiredType, args, false);
           }

          所有最終獲取bean的方法都是

           protected <T> T doGetBean(
             String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
             throws BeansException {

          這個方法,這個方法是protected的,是不對外提供的。所以我們不能直接調(diào)用它,只能通過上面提供的5個方法來獲取bean對象。

          (2)下面我們從doGetBean這里來看下serviceA創(chuàng)建的過程

           protected <T> T doGetBean(
             String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
             throws BeansException {
             //如果bean之前存在,這里返回的shareInstance就是非空,就會從后面的if分支中返回,如果bean之前不存在,就會執(zhí)行后面的bean創(chuàng)建及注入屬性的過程
             Object sharedInstance = getSingleton(beanName);
             if (sharedInstance != null && args == null) {
             ......
             //如果當(dāng)前不只是檢查,而且是創(chuàng)建bean,這個參數(shù)就是false,在這里就會做個bean創(chuàng)建的標(biāo)記,把beanName 加到alreadyCreated里面去
             if (!typeCheckOnly) {
              markBeanAsCreated(beanName);
             }
              //我們當(dāng)前要創(chuàng)建的bean是單例的,就會走到這里去,下面我們走到里面的調(diào)用去看看
              // Create bean instance.
              if (mbd.isSingleton()) {
               sharedInstance = getSingleton(beanName, () -> {
                try {
                 return createBean(beanName, mbd, args);
                }
                catch (BeansException ex) {
                 // Explicitly remove instance from singleton cache: It might have been put there
                 // eagerly by the creation process, to allow for circular reference resolution.
                 // Also remove any beans that received a temporary reference to the bean.
                 destroySingleton(beanName);
                 throw ex;
                }
               });
               beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
              }

            }
           public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
            Assert.notNull(beanName, "Bean name must not be null");
            synchronized (this.singletonObjects) {
                          ......
                          //這里會把當(dāng)前bean的名字加入到當(dāng)前正在創(chuàng)建的單例對象集合singletonsCurrentlyInCreation中
              beforeSingletonCreation(beanName);
              ......
              try {
                              //這里就是調(diào)用上面的return createBean(beanName, mbd, args);這個方法,我們進(jìn)這里面去看看
               singletonObject = singletonFactory.getObject();
               newSingleton = true;
              }
              ......
             }
             return singletonObject;
            }
           }

           @Override
           protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
             throws BeanCreationException {
            ......
            // Make sure bean class is actually resolved at this point, and
            // clone the bean definition in case of a dynamically resolved Class
            // which cannot be stored in the shared merged bean definition.
                  //在這里獲取要創(chuàng)建的bean的class對象
            Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
            ......
            try {
                      //調(diào)用這里來創(chuàng)建,我們再走到這里面去看看
                      //3個參數(shù)分別為
                      //1、beanName  bean對象的名字
                      //2、mbdToUseRootBeanDefinition對象,可以認(rèn)為就是bean的元數(shù)據(jù)信息,包含bean的類對象,bean的類上注解,bean實際位置路徑等等
                      //3、args  bean對象的構(gòu)造方法的實參,這里一般是空的
             Object beanInstance = doCreateBean(beanName, mbdToUse, args);
             if (logger.isTraceEnabled()) {
              logger.trace("Finished creating instance of bean '" + beanName + "'");
             }
             return beanInstance;
            }
            ......
           }

          protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
                throws BeanCreationException {

             ......
             //真正創(chuàng)建bean對象是在這里,這里返回的instanceWrapper是bean對象的類實例的包裝對象BeanWrapper
             if (instanceWrapper == null) {
                instanceWrapper = createBeanInstance(beanName, mbd, args);
             }
             //這里的bean就是實際創(chuàng)建的bean對象的類實例
             Object bean = instanceWrapper.getWrappedInstance();
             Class<?> beanType = instanceWrapper.getWrappedClass();
             if (beanType != NullBean.class) {
                mbd.resolvedTargetType = beanType;
             }
           ......
             // Eagerly cache singletons to be able to resolve circular references
             // even when triggered by lifecycle interfaces like BeanFactoryAware.
             //看上面的注釋大概也能明白, 大概意思就是早期的單例緩存,為了解決由 BeanFactoryAware等等觸發(fā)的循環(huán)依賴
             //mbd.isSingleton()  表示bean是單例的(這個是bean對應(yīng)的類上的,默認(rèn)就是單例),
             //this.allowCircularReferences 允許循環(huán)引用,這個是beanFactory的成員屬性,默認(rèn)也是true
             //isSingletonCurrentlyInCreation(beanName) 表示是否在當(dāng)前正在創(chuàng)建的bean集合中。beforeSingletonCreation(beanName);我們在前面執(zhí)行過這句就加到正在創(chuàng)建的bean集合中了
             //這里earlySingletonExposure 就是true了,會進(jìn)到if分支中
             boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                   isSingletonCurrentlyInCreation(beanName));
             if (earlySingletonExposure) {
                if (logger.isTraceEnabled()) {
                   logger.trace("Eagerly caching bean '" + beanName +
                         "' to allow for resolving potential circular references");
                }
                //這句主要是將將() -> getEarlyBeanReference(beanName, mbd, bean) 這個lambda表達(dá)式存儲到this.singletonFactories集合中
                addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
             }

             // Initialize the bean instance.
             Object exposedObject = bean;
             try {
                //在這里就會進(jìn)行屬性填充,完成成員注入等等,也就是在這里serviceA這個bean會注入serviceB這個成員屬性,我們走進(jìn)這個方法去看看
                populateBean(beanName, mbd, instanceWrapper);
                ......
             }
            ......

             return exposedObject;
          }
           protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
            ......
            if (hasInstAwareBpps) {
             if (pvs == null) {
              pvs = mbd.getPropertyValues();
             }
             //真正的屬性注入是在這里完成的,aop也是在這里來完成的。這里是獲取beanFactory中的InstantiationAwareBeanPostProcessor對bean對象進(jìn)行增強(qiáng)
             //如果屬性注入用的是@Resource,就會用CommonAnnotationBeanPostProcessor來完成
             //如果屬性注入用的是@Autowired,就會用AutowiredAnnotationBeanPostProcessor來完成
             //如果是AOP 就會使用InfrastructureAdvisorAutoProxyCreator來生成對應(yīng)的代理對象
             //我們這里使用的是@Autowired,所以會用AutowiredAnnotationBeanPostProcessor來完成注入。我們走到它的postProcessProperties的去看看
             for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
              PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
              ......
           }
           @Override
           public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
                  //這里主要是獲取bean的類屬性和方法上的org.springframework.beans.factory.annotation.Autowired,org.springframework.beans.factory.annotation.Value注解來進(jìn)行注入
            InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
            try {
                      //繼續(xù)進(jìn)去看看
             metadata.inject(bean, beanName, pvs);
            }
            ......
           }
          public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
             ......
             //對每一個屬性分別進(jìn)行注入,繼續(xù)進(jìn)去
                   element.inject(target, beanName, pvs);
                }
             }
          }

              @Override
              protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
               Field field = (Field) this.member;
               Object value;
               //如果之前緩存過就從緩存取,我們是第一次注入,所以之前沒有緩存,不會走這個分支
               if (this.cached) {
                try {
                 value = resolvedCachedArgument(beanName, this.cachedFieldValue);
                }
                catch (NoSuchBeanDefinitionException ex) {
                 // Unexpected removal of target bean for cached argument -> re-resolve
                 value = resolveFieldValue(field, bean, beanName);
                }
               }
               else {
                //會走這里來解析字段的值,再進(jìn)去
                value = resolveFieldValue(field, bean, beanName);
               }
               if (value != null) {
                ReflectionUtils.makeAccessible(field);
                field.set(bean, value);
               }
              }


            @Nullable
            private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
             //創(chuàng)建字段的包裝類DependencyDescriptor
             DependencyDescriptor desc = new DependencyDescriptor(field, this.required);

             try {
              //調(diào)用這里完成對應(yīng)字段值的查找,再進(jìn)去
              value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
             }
             catch (BeansException ex) {
              throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
             }
             synchronized (this) {
              //獲取到值之后,進(jìn)行緩存
              if (!this.cached) {
                ......
               }
               this.cachedFieldValue = cachedFieldValue;
               this.cached = true;
              }
             }
             return value;
            }
           }
           public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
             @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {

            descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
            if (Optional.class == descriptor.getDependencyType()) {
             return createOptionalDependency(descriptor, requestingBeanName);
            }
            else if (ObjectFactory.class == descriptor.getDependencyType() ||
              ObjectProvider.class == descriptor.getDependencyType()) {
             return new DependencyObjectProvider(descriptor, requestingBeanName);
            }
            else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
             return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
            }
            else {
             //當(dāng)前的類是一個普通的class,會走到這里面,由于我們的bean沒有Lazy注解,所以這里返回時null,走到下面的if分支
             Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
               descriptor, requestingBeanName);
             if (result == null) {
              //在這里我們看下這里的入?yún)ⅰ?br>    //descriptor是包含了需要注入的字段的信息。
              //requestingBeanName是當(dāng)前正在創(chuàng)建的bean的名字serviceA,
              //autowiredBeanNames是當(dāng)前需要注入的字段的對應(yīng)的bean的名字的集合,這里只有serviceB
              //typeConverter這個是進(jìn)行注入時做類型轉(zhuǎn)換的,這里我們可以不用關(guān)注這個
              result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
             }
             return result;
            }
           }
           @Nullable
           public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
             @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
             ......
             if (instanceCandidate instanceof Class) {
              //又會調(diào)用到這里,我們再進(jìn)入到DependencyDescriptor的resolveCandidate去看看
                          //注意:這里的autowiredBeanName是我們需要注入的屬性名這里是serviceB
              instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
             }
             ......
           }

           public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
             throws BeansException {
            //看到?jīng)],到這里就出現(xiàn)循環(huán)調(diào)用了,到這里又會重新調(diào)用beanFactory.getBean("serviceB")去創(chuàng)建serviceB的bean對象,完成后注入到serivceA對應(yīng)的Bean上的屬性上來,這時代碼又會從本節(jié)開頭的位置開始執(zhí)行,先創(chuàng)建serviceB對象實例,再去注入serviceB對象的serviceA屬性。
                  //最終會執(zhí)行到beanFactory.getBean("serviceA")這里
            return beanFactory.getBean(beanName);
           }

          就是下面圖的樣子

          3、解決循環(huán)依賴的代碼實現(xiàn)

          接著上面的beanFactory.getBean("serviceA")這行代碼我們繼續(xù)往下看

          這次又會走到這里

           protected <T> T doGetBean(
             String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
             throws BeansException {
            //我們第二部分就是從這里開始的,又走回來了,但這次又會有所不同
            String beanName = transformedBeanName(name);
            Object beanInstance;

            // Eagerly check singleton cache for manually registered singletons.
            //這次我們這里返回的就不是空了,sharedInstance對象的值就是對應(yīng)serviceA的bean對象了,這次就會從if分支中返回,而之前我們不會進(jìn)這里的if分支而是進(jìn)入else分支導(dǎo)致后面出現(xiàn)了循環(huán)依賴的問題,這次我們進(jìn)到這個方法看看
            Object sharedInstance = getSingleton(beanName);
            if (sharedInstance != null && args == null) {
             if (logger.isTraceEnabled()) {
              if (isSingletonCurrentlyInCreation(beanName)) {
               logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                 "' that is not fully initialized yet - a consequence of a circular reference");
              }
              else {
               logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
              }
             }
             beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
            }
           @Nullable
           public Object getSingleton(String beanName) {
            //再點進(jìn)去
            return getSingleton(beanName, true);
           }
           protected Object getSingleton(String beanName, boolean allowEarlyReference) {
            // Quick check for existing instance without full singleton lock
            Object singletonObject = this.singletonObjects.get(beanName);
                   //這里由于當(dāng)前的serviceA bean還沒完成創(chuàng)建,所以這里singletonObject返回的是空,
                  //再看看 isSingletonCurrentlyInCreation(beanName)這里,由于我們在創(chuàng)建serviceA過程中有這么一句beforeSingletonCreation(beanName)(不清楚這句的搜索下本文,上面就有講到),所有這個條件是true。這時我們就會進(jìn)入if分支中
            if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
             singletonObject = this.earlySingletonObjects.get(beanName);
                     //由于我們是第一次進(jìn)入這里,所以this.earlySingletonObjects.get(beanName)返回的也是null
                     //我們的入?yún)?nbsp;allowEarlyReference是true,會繼續(xù)進(jìn)到這個if分支中
             if (singletonObject == null && allowEarlyReference) {
              synchronized (this.singletonObjects) {
               // Consistent creation of early reference within full singleton lock
               singletonObject = this.singletonObjects.get(beanName);
                              //這里的singletonObject還是null,繼續(xù)進(jìn)到if分支
               if (singletonObject == null) {
                singletonObject = this.earlySingletonObjects.get(beanName);
                if (singletonObject == null) {
                                      //最終會走到這里,在創(chuàng)建serviceA對象之后,屬性注入之前,執(zhí)行了這句 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))(不清楚的搜索下本文,上面有說到),所以這里返回的singletonFactory是個lamdba表達(dá)式,getEarlyBeanReference(beanName, mbd, bean))附帶了3個參數(shù),第一個beanName是serivceA,mdb是對應(yīng)serviceA的附帶serviceA元數(shù)據(jù)信息的RootBeanDefinition對象,bean就是創(chuàng)建出來的serviceA對象
                 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                 if (singletonFactory != null) {
                                          //這里就會調(diào)用getEarlyBeanReference(beanName, mbd, bean)對serviceA對象進(jìn)行一個getEarlyBeanReference增強(qiáng)后返回,返回后放置到earlySingletonObjects中,并從singletonFactories中刪除
                  singletonObject = singletonFactory.getObject();
                  this.earlySingletonObjects中,并從.put(beanName, singletonObject);
                  this.singletonFactories.remove(beanName);
                 }
                }
               }
              }
             }
            }
            return singletonObject;
           }

          最終在serviceA 這個bean創(chuàng)建完成后,就會從singletonsCurrentlyInCreation移除掉

           public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
              ......
              finally {
               //在這里從singletonsCurrentlyInCreation中移除掉
               afterSingletonCreation(beanName);
              }
              if (newSingleton) {
               //將serviceA bean對象添加到singletonObjects,registeredSingletons中
               //從singletonFactories,earlySingletonObjects中移除掉
               addSingleton(beanName, singletonObject);
              }
             }
             return singletonObject;
            }
           }

          所以整個獲取serviceA的流程就是這樣了,

          1、首先去創(chuàng)建serviceA這個bean,

          • 由于它有個屬性serviceB,在創(chuàng)建完serviceA對象后,就會去進(jìn)行serviceB的屬性注入,

          • 這時由于serviceB之前沒有生成,這時又會去創(chuàng)建serviceB這個bean,

          • 先創(chuàng)建serviceB對象,然后再進(jìn)行serviceA這個屬性的注入,

          • 繼續(xù)去獲取serviceA這個bean,第二次進(jìn)入獲取serviceA的流程,這時從之前緩存的lambda表達(dá)式中獲取到之前創(chuàng)建的serviceA的引用返回。

          2、總結(jié)下關(guān)鍵的代碼點

          • 創(chuàng)建bean對象之前調(diào)用beforeSingletonCreation(beanName)將bean對象名字添加到singletonsCurrentlyInCreation集合中

          • 創(chuàng)建bean對象對應(yīng)的類實例后調(diào)用addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));添加到singletonFactories中

          • 在循環(huán)依賴中第二次調(diào)用到創(chuàng)建bean對象時,調(diào)用getSingleton(beanName, true)時,從singletonFactories中返回對應(yīng)的早期bean對象的引用,并添加到earlySingletonObjects中






          瀏覽 62
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美 国产 综合 | 男人天堂国产精品 | 小骚逼网站 | 大鸡巴操小穴 | 人人操人人泡 |