<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      轉載和引用,請注明原文出處! Fork me on GitHub
      結局很美妙的事,開頭并非如此!

      框架源碼系列九:依賴注入DI、三種Bean配置方式的注冊和實例化過程

      一、依賴注入DI

      學習目標
      1)搞清楚構造參數依賴注入的過程及類
      2)搞清楚注解方式的屬性依賴注入在哪里完成的。
      學習思路
      1)思考我們手寫時是如何做的
      2)讀 spring 源碼對比看它的實現
      3)Spring 源碼解讀

      1. 構造參數依賴注入

      org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(String, RootBeanDefinition, Constructor<?>[], Object[])

      ->
      org.springframework.beans.factory.support.ConstructorResolver.resolveConstructorArguments(String, RootBeanDefinition, BeanWrapper, ConstructorArgumentValues, ConstructorArgumentValues)

      、、

      ->
      org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(Object, Object)

       

       解析構造參數源代碼的使用示例:

          <bean id="combatService" factory-bean="loveServiceFactory" 
              factory-method="getCombatServiceFromMemberFactoryMethod" >
              <constructor-arg type="int" value="120" />
              <constructor-arg ref="beanA"></constructor-arg>
              <constructor-arg><bean id="ssss" class="cccc"></bean></constructor-arg>
              <constructor-arg><bean class="cccc"></bean></constructor-arg>
              <constructor-arg><map></map></constructor-arg>
              <constructor-arg><list></list></constructor-arg>
          </bean>

      拓展:初始化前初始化后處理

      實現BeanPostProcessor然后在里面的初始化前和初始化后的方法里面打斷點看調用棧就可以找到初始化前和初始化后在哪里處理的了

       實現BeanPostProcessor:

      package com.study.leesmall.spring.ext;
      
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanPostProcessor;
      import org.springframework.stereotype.Component;
      
      @Component
      public class MyBeanPostProcessor implements BeanPostProcessor {
      
          public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              System.out.println("------MyBeanPostProcessor.postProcessBeforeInitialization for " + beanName);
              return bean;
          }
      
          public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              System.out.println("------MyBeanPostProcessor.postProcessAfterInitialization for " + beanName);
              return bean;
          }
      }

      在初始化前方法MyBeanPostProcessor.postProcessBeforeInitialization和MyBeanPostProcessor.postProcessAfterInitialization里面打斷點拿到調用棧:

      初始化前調用棧:

       

      具體的初始化前處理:

       初始化后調用棧:

       具體的初始化后處理:

       

      2、屬性依賴注入

      寫個測試類里面含有get和set方法,然后在set方法里面打個斷點拿到調用棧去分析

      測試類:

      import org.springframework.stereotype.Component;
      
      @Component
      public class Bean3 {
          private String value;
      
          public String getValue() {
              return value;
          }
      
          public void setValue(String value) {
              this.value = value;
          }
      }

      在xml里面的配置:

          <bean id="bean3" class="com.study.leesmall.spring.sample.di.Bean3" scope="prototype" >
              <property name="value" value="10"></property>
          </bean>

      測試入口:

      package com.study.leesmall.spring.sample.di;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.GenericXmlApplicationContext;
      
      public class DiMain {
      
          public static void main(String[] args) {
              ApplicationContext context = new GenericXmlApplicationContext(
                      "classpath:com/study/leesmall/spring/sample/di/application.xml");
      
              Bean3 b3 = context.getBean(Bean3.class);
          }
      }

      在set方法里面打個斷點拿到調用棧:

       

      屬性依賴值處理源碼分析:

      org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(String, RootBeanDefinition, BeanWrapper)

       

      3. 屬性循環依賴怎么處理

      構成參數是不允許循環依賴的,屬性是允許循環依賴的

      1)示例代碼

      Bean1:

      package com.study.leesmall.spring.sample.di;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Component;
      
      public class Bean1 {
      
          @Autowired
          private Bean2 b2;
      
          public void do1() {
              System.out.println("------------------do1");
          }
      
          public Bean2 getB2() {
              return b2;
          }
      
          public void setB2(Bean2 b2) {
              this.b2 = b2;
          }
      }

      Bean2:

      package com.study.leesmall.spring.sample.di;
      
      import org.springframework.stereotype.Component;
      
      
      public class Bean2 {
      
          @Autowired
          private Bean1 b1;
      
          public void do2() {
              b1.do1();
          }
      
          public Bean1 getB1() {
              return b1;
          }
      
          public void setB1(Bean1 b1) {
              this.b1 = b1;
          }
      }

      /spring-source-study/src/main/java/com/study/leesmall/spring/sample/di/application.xml配置:

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd">
          
          <bean id="bean1" class="com.study.leesmall.spring.sample.di.Bean1" >
              <property name="b2" ref="bean2"></property>
          </bean>
          
          <bean id="bean2" class="com.study.leesmall.spring.sample.di.Bean2" >
              <property name="b1" ref="bean1"></property>
          </bean>
          
          
      </beans>
          
          
          

      測試類DiMain:

      package com.study.leesmall.spring.sample.di;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.GenericXmlApplicationContext;
      
      public class DiMain {
      
          public static void main(String[] args) {
              ApplicationContext context = new GenericXmlApplicationContext(
                      "classpath:com/study/leesmall/spring/sample/di/application.xml");
      
      
              Bean2 b2 = context.getBean(Bean2.class);
              b2.do2();
          }
      }

      2)請分別嘗試在xml配置中配置如下三種情況,看是否可以循環依賴成功

      a)Bean1和Bean2都是單例bean。

        循環依賴成功
      b)Bean1和Bean2一個是單例的,一個是原型的。

        循環依賴成功
      c)Bean1和Bean2都是原型的

        循環依賴不成功

      3)思考:為什么兩個是原型時不能循環依賴,而單例時可以?

      一個Bean的屬性依賴另一個bean實例,注入的過程是否就是從BeanFactory中getBean(),再賦值給屬性?

        是,首先從Bean工廠里面獲取依賴的bean,沒有就創建

      那為什么單例可以,原型不可以?

      依據上面的邏輯,那就單例時可以getBean()獲得依賴的bean實例,原型時不能,為什么?
      再來回想一下單例bean和原型bean在BeanFactory中的區別:

        單例Bean是緩存在BeanFactory中的,而原型Bean是不緩存的。

      緩存和不緩存對于循環依賴的處理有什么不同呢?

      思考一下創建Bean實例的過程:
        先Bean1,創建Bean1的實例——>然后對其屬性進行依賴注入處理——>依賴Bean2,從BeanFactorygetBean("bean2")——>創建Bean2的實例——>對Bean2實例的屬性進行依賴注入處理——>依賴Bean1,從BeanFactory中獲取Bean1的實例
        緩存的就可以通過beanFactory的getBean()獲得前一個Bean的實例。而如果不緩存的,則bean2實例依賴注入Bean1時,從BeanFactorygetBean()就會又創建一個Bean1的實例,如此會無限循環依賴創建下去。

      再仔細想一下,對于單例bean的緩存有時機的要求嗎?
        有,一定要在進行屬性依賴注入處理前緩存(暴露)到BeanFactory中。

      4)看源碼找到單例Bean暴露(緩存)到BeanFactory中的代碼,它應在創建Bean實例后,進行屬性依賴注入前

      在AbstractAutowireCapableBeanFactory.doCreateBean()方法中

              // 為循環引用依賴提前緩存單例 bean
              // Eagerly cache singletons to be able to resolve circular references
              // even when triggered by lifecycle interfaces like BeanFactoryAware.
              // 是否提早暴露單例 Bean 實例
              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");
                  }
                  addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
              }

      5)看一遍屬性注入的代碼邏輯驗證getBean(),單例的獲取

      代碼在AbstractAutowireCapableBeanFactory.populateBean()中。
      Xml配置方式的處理邏輯在方法最后的applyPropertyValues(beanName,mbd,bw,pvs);方法中。
      注解的方式則在之上的InstantiationAwareBeanPostProcessor執行中:

              if (hasInstAwareBpps) {
                  if (pvs == null) {
                      pvs = mbd.getPropertyValues();
                  }
                  for (BeanPostProcessor bp : getBeanPostProcessors()) {
                      if (bp instanceof InstantiationAwareBeanPostProcessor) {
                          InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                          PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                          if (pvsToUse == null) {
                              if (filteredPds == null) {
                                  filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
                              }
                              pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                              if (pvsToUse == null) {
                                  return;
                              }
                          }
                          pvs = pvsToUse;
                      }
                  }
              }

      二、三種 Bean 配置方式的注冊、實例化過程

      1. Xml

       BeanF:

      package com.study.leesmall.spring.sample.config;
      
      import org.springframework.beans.factory.annotation.Autowired;
      
      public class BeanF {
      
          @Autowired
          private BeanE be;
      
          public void do1() {
              System.out.println("----------" + this + " do1");
              this.be.doSomething();
          }
      }

      BeanE:

      package com.study.leesmall.spring.sample.config;
      
      public class BeanE {
      
          public void doSomething() {
              System.out.println("-----" + this + " doSomething ");
          }
      }

      xml配置:

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:context="http://www.springframework.org/schema/context"
          xmlns:aop="http://www.springframework.org/schema/aop"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context.xsd
              http://www.springframework.org/schema/aop
              http://www.springframework.org/schema/aop/spring-aop.xsd">
          
          <bean id="beanE" class="com.study.leesmall.spring.sample.config.BeanE" />
          
          <bean id="beanF" class="com.study.leesmall.spring.sample.config.BeanF" ></bean>
          
          <context:annotation-config/>
          
          <context:component-scan base-package="com.study.leesmall.spring.sample.config" ></context:component-scan>
          
      </beans>
          
          
          

      測試類:

      XMLConfigMain

      package com.study.leesmall.spring.sample.config;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.GenericXmlApplicationContext;
      
      public class XMLConfigMain {
      
          public static void main(String[] args) {
              ApplicationContext context = new GenericXmlApplicationContext(
                      "classpath:com/study/leesmall/spring/sample/config/application.xml");
      
              BeanF bf = context.getBean(BeanF.class);
              bf.do1();
      
          }
      
      }

      測試類運行結果:

      ----------com.study.leesmall.spring.sample.config.BeanF@19d37183 do1
      -----com.study.leesmall.spring.sample.config.BeanE@1a0dcaa doSomething 

      2. Annotation 注解

       BeanG

      package com.study.leesmall.spring.sample.config;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.annotation.ImportResource;
      import org.springframework.stereotype.Component;
      
      @Component
      @ImportResource("classpath:com/study/leesmall/spring/sample/config/application.xml")
      public class BeanG {
      
          @Autowired
          private BeanF beanf;
      
          public void dog() {
              System.out.println("----------------------------------------");
              this.beanf.do1();
          }
      }

      在xml里面開啟注解掃描:

          <context:annotation-config/>
          
          <context:component-scan base-package="com.study.leesmall.spring.sample.config" ></context:component-scan>

      測試類:

      AnnotationMain

      package com.study.leesmall.spring.sample.config;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      
      public class AnnotationMain {
      
          public static void main(String[] args) {
              ApplicationContext context = new AnnotationConfigApplicationContext("com.study.leesmall.spring.sample.config");
      
              BeanG bg = context.getBean(BeanG.class);
              bg.dog();
          }
      }

      測試結果:

      ----------------------------------------
      ----------com.study.leesmall.spring.sample.config.BeanF@6f204a1a do1
      -----com.study.leesmall.spring.sample.config.BeanE@2de56eb2 doSomething 

      3. Java based

       BeanH:

      package com.study.leesmall.spring.sample.config;
      
      import org.springframework.beans.factory.annotation.Autowired;
      
      public class BeanH {
      
          @Autowired
          private BeanE be;
      
          public void doH() {
              System.out.println("-----------" + this + " doH");
              be.doSomething();
          }
      }

      測試類:

      JavaBasedMain

      package com.study.leesmall.spring.sample.config;
      
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      
      @Configuration
      @ComponentScan("com.study.leesmall.spring.sample.config")
      public class JavaBasedMain {
      
          @Bean
          public BeanH getBeanH() {
              return new BeanH();
          }
      
          public static void main(String[] args) {
              ApplicationContext context = new AnnotationConfigApplicationContext(JavaBasedMain.class);
      
              BeanH bh = context.getBean(BeanH.class);
              bh.doH();
          }
      }

      測試結果:

      -----------com.study.leesmall.spring.sample.config.BeanH@475e586c doH
      -----com.study.leesmall.spring.sample.config.BeanE@657c8ad9 doSomething 

      問題:

      1、 xml 方式中怎么開啟注解支持?

      在application.xml里面加入如下配置:

          <context:annotation-config/>
          
          <context:component-scan base-package="com.study.leesmall.spring.sample.config" ></context:component-scan>

      2、xml方式中開啟注解支持,是如何實現的?該怎么去看?你會怎么實現?

      入口在Spring的E:\repository\org\springframework\spring-context\5.1.3.RELEASE\spring-context-5.1.3.RELEASE.jar /META-INF/spring.handlers里面

      http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
      http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
      http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
      http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
      http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler

      ContextNamespaceHandler就是入口:

       

      類org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser就是用來解析下面的配置的:

      <context:annotation-config/>

       

       

      注冊注解配置處理器的方法org.springframework.context.annotation.AnnotationConfigUtils.registerAnnotationConfigProcessors(BeanDefinitionRegistry, Object)

       

      Autowired注解的處理屬性注入的方法:

      org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(PropertyValues, Object, String)

       

      org.springframework.beans.factory.annotation.InjectionMetadata.InjectedElement.inject(Object, String, PropertyValues):

      3、Xml中的<context:component-scan>是如何實現的?
      4、注解方式可以嵌入xml嗎?
      5、Javabase方式各注解的解析發生在哪

       

      posted @ 2019-03-17 10:53  小不點啊  閱讀(1121)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产精品制服丝袜白丝| 乱码中文字幕| 亚洲精品一区久久久久一品av| 久久综合色一综合色88欧美| 加勒比无码人妻东京热| 日本一区二区精品色超碰| 久久精品熟妇丰满人妻久久| 思思热在线视频精品| 一本色道久久加勒比综合| 日日噜久久人妻一区二区| 欧美牲交a欧美在线| 久色伊人激情文学你懂的| 精品九九人人做人人爱| 在线亚洲人成电影网站色www| 无人区码一码二码三码区| 亚洲理论在线A中文字幕| 绥滨县| 国产亚洲999精品AA片在线爽| 日韩剧情片电影网站| 亚洲最大成人免费av| 国产视频一区二区三区视频| 无码吃奶揉捏奶头高潮视频| 久热久热中文字幕综合激情 | 熟妇的味道hd中文字幕| 日本亚洲一区二区精品久久| 亚洲区一区二区激情文学| 国产精品三级中文字幕| 99RE8这里有精品热视频| 国产精品毛片一区视频播| 久久久精品国产精品久久| 一区二区不卡国产精品| 亚洲综合不卡一区二区三区| 久久精品国产精品亚洲毛片| 91人妻无码成人精品一区91| 丰满岳乱妇三级高清| 国产国语一级毛片| 内射老阿姨1区2区3区4区| 在线看免费无码的av天堂| 国内精品免费久久久久电影院97| 国内精品久久久久影院薰衣草| 亚洲av成人网人人蜜臀|