<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>

          Spring是如何解決循環(huán)依賴的呢?

          共 47131字,需瀏覽 95分鐘

           ·

          2021-05-20 23:03

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

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

          76套java從入門到精通實戰(zhàn)課程分享

          1、什么是循環(huán)依賴?

          循環(huán)依賴就是循環(huán)引用,就是兩個或多個bean相互之間的持有對方。
          A類中有一個B類型的成員變量,需要注入B
          B類中有一個A類型的成員變量,需要注入A

          2、循環(huán)依賴的場景

          2.1、構(gòu)造器的循環(huán)依賴【spirng無法解決】

          兩個循環(huán)依賴的類

          //A類
          public Class A{
              private B b;
              
           pubcli A(B b){
                  this.b=b;
              }
          }
          //B類
          public Class B{
              private A a;
              public B(A a){
                 this. a=a;
              }
              
          }

          xml配置信息為

          <bean id="a" class="com.make.spring.A">
              <constructor-arg name="b" ref="b"></constructor-arg>
          </bean>  
          <bean id="b" class="com.make.spring.B">
              <constructor-arg name="a" ref="a"></constructor-arg>
          </bean>

          主方法的內(nèi)容如下

          public static void main(String[] args) {
           ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springConstructor.xml");
           A bean = context.getBean(A.class);
           System.out.println(bean);
          }

          啟動報錯信息如下:

          spring是無法解決構(gòu)造函數(shù)循環(huán)依賴注入的,因為這種時候,在實例化A的時候就要獲取B的實例化對象,在實例化B的時候要A的實例化對象,所以無法創(chuàng)建任何一個實例。

          2.2、setter方法注入屬性,singleton單例模式

          public class A {
           private B b;

           public void setB(B b) {
            this.b = b;
           }

           public B getB() {
            return b;
           }
          }

          public class B {
           private A a;

           public void setA(A a) {
            this.a = a;
           }

           public A getA() {
            return a;
           }
          }

          xml配置信息

          <bean id="a" class="com.make.bean.A">
              <property name="b" ref="b"></property>
          </bean>
          <bean id="b" class="com.make.bean.B">
              <property name="a" ref="a"></property>
          </bean>

          主方法信息

          public static void main(String[] args) {
           ClassPathXmlApplicationContext context=new ClassPathXmlApplicationContext("spring.xml");
           A beanA =context.getBean(A.class);
           System.out.println(beanA.getB());
           B beanB=context.getBean(B.class);
           System.out.println(beanB.getA());
          }

          最后成功的打印信息

          這種情況下,spirng將A的對象實例化后,還未注入屬性的A提前緩存起來,也就是提前暴露A,然后讓B的實例化過程拿到A來解決依賴注入。

          2.3、setter方式,prototype原型模式【spirng無法解決】

          兩個java類的內(nèi)容和主方法的內(nèi)容和1.2的相同

          xml配置信息

          <bean id="a" class="com.make.bean.A" scope="prototype">
              <property name="b" ref="b"></property>
          </bean>
          <bean id="b" class="com.make.bean.B"  scope="prototype">
              <property name="a" ref="a"></property>
          </bean>

          最后顯示的錯誤信息如下:

          對于“prototype”作用域Bean,Spring容器無法完成依賴注入,因為“prototype”作用域的Bean,Spring容器不進(jìn)行緩存,因此無法提前暴露一個創(chuàng)建中的Bean。

          3、單例setter方法注入—循環(huán)依賴解決方法

          3.1、使用緩存解決循環(huán)依賴

          整個spring創(chuàng)建bean對象的步驟主要是如下三三步

          然后我們在和創(chuàng)建A對象的時候,注入屬性時,需要獲取B對象,在注入B的時候獲取A對象,會造成循環(huán)

          那么這個時候他spring提供了一個緩存來解決這種循環(huán)的問題

          在A對象實例化完后,就先將A對象存入到緩存中暴露出來,讓B可以拿到A,拆除循環(huán)。
          spring的對于解決循環(huán)依賴,設(shè)置了三級緩存,用來存儲不同時期的對象。

          3.1、三級緩存

          spring的三級循環(huán)分別為

           /** 一級緩存
            * 單例對象緩存:bean name --> bean的完整實例*/
           private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
           
           /** 三級緩存
            * 保存BeanName于創(chuàng)建bean工程之間的緩存:bean name --> 對象工程,lambda表達(dá)式*/
           private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

           /**  二級緩存
           * 保存單例對象的半成品:bean name--> 半成品bean(bean實例化好后,沒有進(jìn)行屬性填充,沒有初始化的半成品對象)*/
           private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

          3.2、代碼執(zhí)行過程示意圖

          我這里的代碼運行過程是按照上面1.2的代碼進(jìn)行說明的。

          4、依賴注入具體執(zhí)行方法

          4.1、調(diào)用ClassPathXmlApplicationContext的構(gòu)造方法

          public ClassPathXmlApplicationContext(
              String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
              throws BeansException {
              
              super(parent);
              //存儲spring配置文件的路徑到本地
              setConfigLocations(configLocations);
              //判斷是否需要需要重新刷新spring容器——ApplicationContext
              if (refresh) {
                  //刷新spring容器,加載bean的核心方法,刷新spring上下文信息,定義了上下文加載流程——ApplicationContext
                  refresh();
              }
          }

          refresh ApplicationContext,重新刷新Spring容器,注入必要的類、加載bean的一些配置、并實例化bean。
          因為AbstractApplicationContext是ClassPathXmlApplicationContext的父類,所以調(diào)用的是AbstractApplicationContext的refresh方法

          4.2、進(jìn)入到AbstractApplicationContext類的refresh()方法

          @Override
          public void refresh() throws BeansException, IllegalStateException {
           synchronized (this.startupShutdownMonitor) {
            /**
             * 1、設(shè)置容器的啟動時間
             * 2、設(shè)置活躍狀態(tài)為true
             * 3、設(shè)置關(guān)閉狀態(tài)為false
             * 4、獲取Environment對象,并加載當(dāng)前系統(tǒng)的屬性到Environment對象中
             * 5、準(zhǔn)備監(jiān)聽器和時間的結(jié)合對象,默認(rèn)為空的集合
             */
            // Prepare this context for refreshing.
            prepareRefresh();
            
            //創(chuàng)建容器對象:DefaultListableBeanFactory
            //加載xml文件的屬性,最終要的就是BeanDefinition
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            //beanFacotry的準(zhǔn)備工作,對各種屬性進(jìn)行填充
            prepareBeanFactory(beanFactory);
            try {
             //子類覆蓋方法做額外的處理,此出我們一般不做任何擴(kuò)展工作,可以查看web的代碼,是有具體實現(xiàn)
             postProcessBeanFactory(beanFactory);
             
             //調(diào)用Bean工廠的后置處理器
             invokeBeanFactoryPostProcessors(beanFactory);
             
             //注冊BeanPostProcessor 自定義以及spring內(nèi)部的
             registerBeanPostProcessors(beanFactory);

             //  初始化此上下文的消息源
             initMessageSource();

             // 初始化事件監(jiān)聽多路廣播器
             initApplicationEventMulticaster();

             // 留給子類來初始化其他的bean
             onRefresh();
                         
             //在所有注冊的bean中查找listener bean,注冊到消息廣播中
             registerListeners();

             //初始化剩下的單實例(非懶加載的)
             finishBeanFactoryInitialization(beanFactory);

             //完成刷新過程,通知生命周期處理器lifecycleProcessor刷新過
             finishRefresh();
            }
           ........
          }

          其中的核心代碼為換初始化剩下的單實例(非懶加載的),也就是43行。
          是整個spring容器初始化的核心流程。

          4.3、進(jìn)入到finishBeanFactoryInitialization方法

          protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
              ......
              // Instantiate all remaining (non-lazy-init) singletons.
              //實例化剩下的單例對象
              beanFactory.preInstantiateSingletons();
          }

          那么這個方法里面涉及到實例化的就是beanFactory.preInstantiateSingletons();——實例化剩下的單例對象。

          由于ConfigurableListableBeanFactory的實現(xiàn)類為DefaultListableBeanFactory,所以之間調(diào)用DefaultListableBeanFactory的preInstantiateSingletons方法。

          4.4、進(jìn)入到preInstantiateSingletons方法

          @Override
          public void preInstantiateSingletons() throws BeansException {
              if (logger.isDebugEnabled()) {
                  logger.debug("Pre-instantiating singletons in " + this);
              }

              //將所有的BeanDefinition的名字創(chuàng)建一個集合,beanNames獲取到的是[a,b]
              List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

              //觸發(fā)所有非延遲加載單例bean的初始化,遍歷集合
              for (String beanName : beanNames) {
                  //合并父類BeanDefinition
                  //Bean定義的公共抽象類是AbstractBeanDefinition,普通的bean在spring加載bean定義的時候,實例化出來的是GenericBeanDefinition,而Spring上下文
                  //所有bean用的AbstractBeanDefintion是RootBeanDefinition,這個時候需要轉(zhuǎn)換一些,將非RootBeanDefinition轉(zhuǎn)成RootBeanDefinition進(jìn)行后續(xù)操作
                  RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
                  //條件判斷,抽象,單例,非懶加載
                  if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
                      //判斷是否實現(xiàn)了FactoryBean接口
                      if (isFactoryBean(beanName)) {
                          //根據(jù)&+beanName來獲取具體的對象
                          Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
                          if (bean instanceof FactoryBean) {
                              final FactoryBean<?> factory = (FactoryBean<?>) bean;
                              boolean isEagerInit;
                              if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                                  isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                                                                              ((SmartFactoryBean<?>) factory)::isEagerInit,
                                                                              getAccessControlContext());
                              }
                              else {
                                  isEagerInit = (factory instanceof SmartFactoryBean &&
                                                 ((SmartFactoryBean<?>) factory).isEagerInit());
                              }
                              //如果急切的希望初始化,通過beanName獲取bean的實例
                              if (isEagerInit) {
                                  getBean(beanName);
                              }
                          }
                      }
                      else {
                          //如果beanName對應(yīng)的bean不是FactoryBean,只是普通的bean,通過beanName獲取bean實例
                          getBean(beanName);
                      }
                  }
              }

              //遍歷beanNames,觸發(fā)所有的SmartInitializingSingleton的后初始化毀掉
             ......
          }

          這個時候beanNames一共有兩個一個是a,一個是b,
          那么先獲取a。

          4.4.1、第一個判斷

          a不是抽象,也不是懶加載,是單例,所以會走進(jìn)

          if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) 

          4.4.2、第二個判斷

          a沒有實現(xiàn)FactoryBean接口所以直接執(zhí)行g(shù)etBean(a)

          if (isFactoryBean(beanName)) {
           ......
          }
          else {
              //如果beanName對應(yīng)的bean不是FactoryBean,只是普通的bean,通過beanName獲取bean實例
              getBean(beanName);
          }

          4.5、進(jìn)入到getBean方法

          @Override
          public Object getBean(String name) throws BeansException {
           //此方法獲取實際bean的方法,也是觸發(fā)依賴注入的方法
           return doGetBean(name, null, null, false);
          }

          直接調(diào)用doGetBean

          4.6、進(jìn)入到dogetBean方法

          @SuppressWarnings("unchecked")
          protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
                                    @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
              //提取對應(yīng)的beanName
              final String beanName = transformedBeanName(name);
              Object bean;
              // Eagerly check singleton cache for manually registered singletons.
              //提前檢查單例緩存中是否有手動注冊的單例對象,跟循環(huán)依賴有關(guān)聯(lián)——6.1
              Object sharedInstance = getSingleton(beanName);
              //如果bean的單例對象找到了,且沒有創(chuàng)建bean實例時要使用的參數(shù)
              if (sharedInstance != null && args == null) {
            .....
              }
              else {
                  //判斷我們是不是正在創(chuàng)建這個實例,如果是失敗,應(yīng)該是在循環(huán)參考之內(nèi)
                  if (isPrototypeCurrentlyInCreation(beanName)) {
                      throw new BeanCurrentlyInCreationException(beanName);
                  }

                  //檢查該工廠中是否存在bean定義
                  BeanFactory parentBeanFactory = getParentBeanFactory();
                  if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
                      .....
                  }
                  //如果不是做類型檢查,那么就用創(chuàng)建bean,此處在集合中做一個記錄
                  if (!typeCheckOnly) {
                      markBeanAsCreated(beanName);
                  }

                  try {
                      //此處做了BeanDefinition對象的轉(zhuǎn)換,當(dāng)我們從xml文件中加載BeanDefinition對象的時候,封裝的對象時GenericBeanDefinition,
                      //此處要做類型轉(zhuǎn)換,如果是子類bean的話,去合并父類的相關(guān)屬性
                      final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                      checkMergedBeanDefinition(mbd, beanName, args);

                      ......

                      // Create bean instance.
                      //創(chuàng)建bean的實例對象,這里都可mdb就是RootBeanDefinition,也就是bean相關(guān)的一些定義信息
                      if (mbd.isSingleton()) {
                          //返回以beanName的(原始)單例對象,如果尚未注冊,使用singletonFactory創(chuàng)建并注冊一個對象
                          sharedInstance = getSingleton(beanName, () -> {
                              try {
                                  //為給定的合并后的BeanDefinition(和參數(shù))創(chuàng)建一個bean實例
                                  return createBean(beanName, mbd, args);
                              }
                              catch (BeansException ex) {
                                  //顯示地從單例緩存中刪除實例,可能是由創(chuàng)建過程急切地放在那里,以允許循環(huán)引用解析,還要刪除
                                  //接收該bean臨時引用的任何bean
                                  //銷毀給定的bean,如果找到響應(yīng)的一次性bean實例,委托給destoryBean
                                  destroySingleton(beanName);
                                  //重新拋出ex
                                  throw ex;
                              }
                          });
                          bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
                      }
                      ......
                  }
                  catch (BeansException ex) {
                      cleanupAfterBeanCreationFailure(beanName);
                      throw ex;
                  }
              }
              .....
              return (T) bean;
          }

          進(jìn)入到doGetBean,這個時候才是真正獲取bean的時候

          4.6.1、先嘗試從緩存中獲取bean——getSingleton(beanName)

           //提前檢查單例緩存中是否有手動注冊的單例對象
          Object sharedInstance = getSingleton(beanName);

          具體這塊執(zhí)行的代碼是

          @Nullable
          protected Object getSingleton(String beanName, boolean allowEarlyReference) {
              //從單例對象緩存中獲取beanName對應(yīng)的單例對象<<一級緩存>>
              Object singletonObject = this.singletonObjects.get(beanName);
              //如果單例對象緩存中沒有,并且該beanName對應(yīng)的單例bean正在創(chuàng)建中
              if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
                  //如果為空,則鎖定全局變量并進(jìn)行處理
                  synchronized (this.singletonObjects) {
                      //從早期單例對象緩存中獲取單例對象(之所以被稱為早期單例對象,是因為earlySingletonObjects里
                      // 的所有對象都是通過提前曝光的ObjectFactory創(chuàng)建出來的,還未進(jìn)行屬性填充等操作)
                      singletonObject = this.earlySingletonObjects.get(beanName);
                      //如果早期單例對象緩存中也沒有,并且允許創(chuàng)建早期單例對象引用
                      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;
          }

          這個時候一級緩存是沒有a對象的,所以singletonObject獲取的為null
          然后a也沒有在創(chuàng)建過程中,所以直接返回null

          4.6.2、開始調(diào)用getSingleton(beanName,singleFacotry)

          if (mbd.isSingleton()) {
              //返回以beanName的(原始)單例對象,如果尚未注冊,使用singletonFactory創(chuàng)建并注冊一個對象
              sharedInstance = getSingleton(beanName, () -> {
                  try {
                      //為給定的合并后的BeanDefinition(和參數(shù))創(chuàng)建一個bean實例
                      return createBean(beanName, mbd, args);
                  }
                  ......
              });
              bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
          }

          這塊具體執(zhí)行的為

          public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
              //如果beanName為null,拋出異常
              Assert.notNull(beanName, "Bean name must not be null");
              //使用單實例對象的高速緩沖Map作為鎖,保證線程同步
              synchronized (this.singletonObjects) {
                  //從單例對象的高速緩沖Map中獲取beanName對應(yīng)的單例對象
                  Object singletonObject = this.singletonObjects.get(beanName);
                  //如果獲取到的為空
                  if (singletonObject == null) {
                      //如果當(dāng)前在destorySingletons中
                      if (this.singletonsCurrentlyInDestruction) {
                          ......
                      }
                      ......
                      //創(chuàng)建單例之前的回調(diào),默認(rèn)實現(xiàn)將單例注冊為當(dāng)前正在創(chuàng)建中
                      beforeSingletonCreation(beanName);
                      ......
                      try {
                          //從單例工廠中獲取對象
                          singletonObject = singletonFactory.getObject();
                          //生成了新的單例對象的標(biāo)記成true,表示生成了新的單例對象
                          newSingleton = true;
                      }
                      ......
                      finally {
                          //如果沒有抑制異常記錄
                          if (recordSuppressedExceptions) {
                              this.suppressedExceptions = null;
                          }
                          //創(chuàng)建單例后的回調(diào),默認(rèn)實現(xiàn)將單例標(biāo)記為不在創(chuàng)建中
                          afterSingletonCreation(beanName);
                      }
                      //生成了新的單例對象
                      if (newSingleton) {
                          //將beanName和singletonObject的映射關(guān)系添加到該工廠的單例緩存中,也就是一級緩存中
                          addSingleton(beanName, singletonObject);
                      }
                  }
                  return singletonObject;
              }
          }

          這個一級緩存獲取到的為null,
          然后將bean的狀態(tài)變成創(chuàng)建中,之后調(diào)用 singletonFactory.getObject()方法。也就是進(jìn)入到傳給getSingleton方法的lamabda的getBean方法

          4.7、進(jìn)入到getBean方法

          @Override
          protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
              throws BeanCreationException {
              ......
              try {
                  //實際創(chuàng)建bean的調(diào)用
                  Object beanInstance = doCreateBean(beanName, mbdToUse, args);
                  if (logger.isDebugEnabled()) {
                      logger.debug("Finished creating instance of bean '" + beanName + "'");
                  }
                  return beanInstance;
              }
              ......
          }

          這里調(diào)用真正創(chuàng)建bean的方法,doGetBean

          4.8、進(jìn)入到doGetBean

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

              //這個beanWrapper是用來持有創(chuàng)建出來的Bean對象的
              BeanWrapper instanceWrapper = null;
              //獲取factoryBean實例緩存
              if (mbd.isSingleton()) {
                  //如果是單例對象,從factorybean實例緩存中移除當(dāng)前bean的定義信息
                  instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
              }
              //如果實例為空
              if (instanceWrapper == null) {
                  //實例化bean
                  //根據(jù)bean使用對應(yīng)的策略創(chuàng)建新的實例,如:工廠方法,構(gòu)造函數(shù)主動注入,簡單初始化
                  instanceWrapper = createBeanInstance(beanName, mbd, args);
              }
              //從包裝類中獲取原始bean
             ......
              
              //運行beanPostProcessor去修改合并的beanDefinition
              ......
              //緩存單例以便處理循環(huán)引用,即使是像BeanFactoryAware這樣的生命周期接口觸發(fā)的
              boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                                isSingletonCurrentlyInCreation(beanName));
              if (earlySingletonExposure) {
                 ......
                  //添加到緩存當(dāng)中
                  addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
              }

              //初始化bean實例
              Object exposedObject = bean;
              try {
                  //注入過程
                  populateBean(beanName, mbd, instanceWrapper);
                  // 將會觸發(fā)postProcessBeforeInitialization和postProcessAfterInitialization
                  exposedObject = initializeBean(beanName, exposedObject, mbd);
              }
              catch (Throwable ex) {
                 ......
              }
              ......
              }
              //注冊完成依賴注入的Bean
              try {
                  registerDisposableBeanIfNecessary(beanName, bean, mbd);
              }
             .....
              return exposedObject;
          }

          4.8.1、開始調(diào)用createBeanInstance(beanName, mbd, args);

          protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
              //解析calss
              Class<?> beanClass = resolveBeanClass(mbd, beanName);

              ......

              // 一個類可能有多個構(gòu)造器,所以Spring得根據(jù)參數(shù)個數(shù)、類型確定需要調(diào)用的構(gòu)造器
              // 在使用構(gòu)造器創(chuàng)建實例后,Spring會將解析過后確定下來的構(gòu)造器或工廠方法保存在緩存中,避免再次創(chuàng)建相同bean時再次解析
              boolean resolved = false;
              boolean autowireNecessary = false;
              if (args == null) {
                  synchronized (mbd.constructorArgumentLock) {
                      //判斷是否有解析的構(gòu)造方法或者工廠方法
                      if (mbd.resolvedConstructorOrFactoryMethod != null) {
                          //已經(jīng)解析過的class構(gòu)造器
                          resolved = true;
                          autowireNecessary = mbd.constructorArgumentsResolved;
                      }
                  }
              }
              //如果解析過
              if (resolved) {
                  ......
              }
              //需要根據(jù)參數(shù)解析、確認(rèn)構(gòu)造器的函數(shù)(從Bean后處理器確定構(gòu)造函數(shù))
              Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
              // 解析的構(gòu)造器不為空 || 注入類型為構(gòu)造函數(shù)自動注入 || bean定義中有構(gòu)造器參數(shù) || 傳入?yún)?shù)不為空
              if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
                 ......
              }

              // No special handling: simply use no-arg constructor.
              //使用默認(rèn)構(gòu)造器
              return instantiateBean(beanName, mbd);
          }

          調(diào)用具體的創(chuàng)建bean的方式,有好幾種,本例子采用的是//使用默認(rèn)構(gòu)造器 return instantiateBean(beanName, mbd); [具體看博客](https://blog.csdn.net/finalcola/article/details/81451019)

          4.8.2、將實例化后的a放入到緩存中

          判斷是否符合需要提前暴露對象,加入緩存的條件

          boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
                                                isSingletonCurrentlyInCreation(beanName));

          • 目前a單例的

          • allowCircularReferences是允許循環(huán)依賴的,這個字段spring默認(rèn)為true,我們也可以通過改變這個字段,而禁止循環(huán)依賴

          • isSingletonCurrentlyInCreation(a),a也是在創(chuàng)建過程中的,在2.3.6的②中已經(jīng)執(zhí)行了將a設(shè)置為創(chuàng)建中的狀態(tài)
            均符合要求所以會執(zhí)行加入緩存的操作

          if (earlySingletonExposure) {
              ......
               //添加到緩存當(dāng)中
               addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
          }

          加入緩存具體執(zhí)行的方法為:

          protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
              Assert.notNull(singletonFactory, "Singleton factory must not be null");
              //使用singletonObjects進(jìn)行加鎖,保證線程安全
              synchronized (this.singletonObjects) {
                  //如果單例對象的高速緩存【Bean名稱-bean實例】沒有beanName對象
                  if (!this.singletonObjects.containsKey(beanName)) {
                      //將beanName.singletonFactory放入到單例工廠的緩存當(dāng)中【bean名稱-ObjectFactory】
                      this.singletonFactories.put(beanName, singletonFactory);
                      //從早期單例對象的高速緩存【bean名稱-bean實例】,移除beanName的相關(guān)緩存對象
                      this.earlySingletonObjects.remove(beanName);
                      //將beanName添加到已注冊的單例集中
                      this.registeredSingletons.add(beanName);
                  }
              }
          }

          下面就該進(jìn)行到調(diào)用populateBean方法為a注入屬性

          4.9、調(diào)用方法populateBean注入屬性

          protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
              // 如果bean實例為空(空實例),并且其屬性不為空,則拋出錯誤,否則跳過
              ......
              // 在設(shè)置屬性之前調(diào)用Bean的PostProcessor后置處理器
              if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
                  for (BeanPostProcessor bp : getBeanPostProcessors()) {
                      if (bp instanceof InstantiationAwareBeanPostProcessor) {
                          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                          if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
                              return;
                          }
                      }
                  }
              }
              // 依賴注入開始,首先處理autowire自動裝配的注入——因為我這里沒有使用autowire所以省略
              ......
              // 檢查容器是否持有用于處理單態(tài)模式Bean關(guān)閉時的后置處理器
              ......
              if (pvs != null) {
                  //主線
                  // 對屬性進(jìn)行注入操作,解決任何在這個bean工廠運行時其他bean的引用,必須使用深拷貝,所以不會永久修改這個屬性
                  applyPropertyValues(beanName, mbd, bw, pvs);
              }
          }

          4.9.1、 調(diào)用設(shè)置xml屬性的核心方法applyPropertyValues

          protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
              //如果pvsPropertyValue
              if (pvs.isEmpty()) {
                  //直接結(jié)束方法
                  return;
              }
              ......
              List<PropertyValue> deepCopy = new ArrayList<>(original.size());
              boolean resolveNecessary = false;
              //遍歷屬性,將屬性轉(zhuǎn)換成對應(yīng)類的對應(yīng)屬性類型
              for (PropertyValue pv : original) {
                  //如果該屬性已經(jīng)被解析過
                  if (pv.isConverted()) {
                      //將pv添加到deepCopy中
                      deepCopy.add(pv);
                  }
                  //如果沒有
                  else {
                      //獲取屬性名
                      String propertyName = pv.getName();
                      //獲取未經(jīng)類型轉(zhuǎn)換的值
                      Object originalValue = pv.getValue();
                      //由valueResolver根據(jù)pv解析出originalValue所封裝的對象
                      Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                     ......
                  }
              }
              ......
          }

          4.9.2、 調(diào)用resolveValueIfNecessary方法解決屬性的值

          @Nullable
          public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
              //如果values是RuntimeBeanReference實例
              if (value instanceof RuntimeBeanReference) {
                  //將value強(qiáng)轉(zhuǎn)成RuntimeBeanReference對象
                  RuntimeBeanReference ref = (RuntimeBeanReference) value;
                  //解析出對應(yīng)的ref所封裝的bean元信息(bean名稱和類型)的Bean對象
                  //處理引用
                  return resolveReference(argName, ref);
              }
              ......
          }

          4.9.3、 調(diào)用解決屬性的ref外部引用resolveReference方法

          @Nullable
          private Object resolveReference(Object argName, RuntimeBeanReference ref) {
              try {
                  //定義一個存儲b對象的變量
                  Object bean;
                  //獲取兩一個bean引用的bean類型
                  String refName = ref.getBeanName();
                  refName = String.valueOf(doEvaluate(refName));
                  //如果引用來自父工廠
                  if (ref.isToParent()) {
                     ......
                  }
                  else {
                      //獲取resolvedName的bean對象
                      bean = this.beanFactory.getBean(refName);
                      //注冊beanName與dependentBeanNamed的依賴關(guān)系到bean工廠
                      this.beanFactory.registerDependentBean(refName, this.beanName);
                  }
                  if (bean instanceof NullBean) {
                      bean = null;
                  }
                  return bean;
              }
              ......
          }

          執(zhí)行到下面的getBean,就開始獲取b

          //獲取resolvedName的bean對象
          bean = this.beanFactory.getBean(refName);

          4.10、創(chuàng)建b的過程

          • 創(chuàng)建b的過程會循環(huán)前面的4.5—4.9.2,直道注入b的屬性時,獲取a,也就是運行到4.9.3的getBean(a)開始獲取b的屬性值a

          • 再次到循環(huán)4.5獲取a對象,也就是b的屬性a的value

          • 這個時候先執(zhí)行4.6.1的getSingleton方法,這個時候a在一級緩存中沒有,但是a是出于創(chuàng)建過程中的,所以可以拿到a
            并將a放入二級緩存,移出三級緩存

          singletonObject = this.earlySingletonObjects.get(beanName);
          //如果早期單例對象緩存中也沒有,并且允許創(chuàng)建早期單例對象引用
          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);
              }
          }

          • 從三級緩存中獲取到a后,再執(zhí)行4.6中的真正獲取工廠中的a的getObjectForBeanInstance方法

          bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

          • 將拿到的a返回到4.9.3的getBean方法中,a的注入屬性完成,之后執(zhí)行4.8的初始化方法

          // 將會觸發(fā)postProcessBeforeInitialization和postProcessAfterInitialization
          exposedObject = initializeBean(beanName, exposedObject, mbd);

          • 將拿到的a返回到4.9.3的getBean方法中,a的注入屬性完成,之后執(zhí)行4.8的初始化方法

          // 將會觸發(fā)postProcessBeforeInitialization和postProcessAfterInitialization
          exposedObject = initializeBean(beanName, exposedObject, mbd);

          • b初始化完成后,返回b對象到4.6.2,將b對象放入到一級緩存中

          //生成了新的單例對象
          if (newSingleton) {
              //將beanName和singletonObject的映射關(guān)系添加到該工廠的單例緩存中,也就是一級緩存中
              addSingleton(beanName, singletonObject);
          }
          //addSingleton方法內(nèi)部執(zhí)行
          protected void addSingleton(String beanName, Object singletonObject) {
              synchronized (this.singletonObjects) {
                  //將映射關(guān)系添加到單例對象的高速緩沖中
                  this.singletonObjects.put(beanName, singletonObject);
                  //移除beanName在三級緩存中的數(shù)據(jù)——工廠緩存
                  this.singletonFactories.remove(beanName);
                  //移除beanName在二級緩存中的對象
                  this.earlySingletonObjects.remove(beanName);
                  //將beanName添加到已經(jīng)注冊的單例集中
                  this.registeredSingletons.add(beanName);
              }
          }

          4.11、將a創(chuàng)建完成

          • b對象創(chuàng)建完成之后,將b對象返回到a的屬性注入時獲取a的getBean(b)方法,將a類似b注入完成后的過程一樣,創(chuàng)建完成a


          版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。

          本文鏈接:

          https://blog.csdn.net/make_1998/article/details/116693232







          鋒哥最新SpringCloud分布式電商秒殺課程發(fā)布

          ??????

          ??長按上方微信二維碼 2 秒





          感謝點贊支持下哈 



          瀏覽 68
          點贊
          評論
          收藏
          分享

          手機(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>
                  青娱乐国产AV | 亚洲精品中文字幕乱码三区91 | 黄色一节片| 人妻AV在线 | 四虎高清无码 |