<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
      結局很美妙的事,開頭并非如此!

      框架源碼系列六:Spring源碼學習之Spring IOC源碼學習

      Spring 源碼學習過程:

      一、搞明白IOC能做什么,是怎么做的

       1. 搞明白IOC能做什么?

         IOC是用為用戶創建、管理實例對象的。用戶需要實例對象時只需要向IOC容器獲取就行了,不用自己去創建,從而達到與具體類解耦?!?/p>

       2. IOC是怎么做到的,即它的實現步驟是怎么樣的?

       

      2.1 用戶配置bean定義

      我們使用Spring IOC時有幾種方式來配置bean定義呢?

      xml的方式:

          <bean id="abean" class="com.study.spring.samples.ABean">
              <constructor-arg type="String" value="abean01"></constructor-arg>
              <constructor-arg ref="cbean"></constructor-arg>
          </bean>
          <bean id="cbean" class="com.study.spring.samples.CBean">
              <constructor-arg type="String" value="cbean01"></constructor-arg>
          </bean>

      注解方式:

      package com.study.spring.samples;
      
      import com.study.spring.context.config.annotation.Autowired;
      import com.study.spring.context.config.annotation.Component;
      import com.study.spring.context.config.annotation.Qualifier;
      import com.study.spring.context.config.annotation.Value;
      
      @Component(initMethodName = "init", destroyMethodName = "destroy")
      public class ABean {
      
          private String name;
      
          private CBean cb;
      
          @Autowired
          private DBean dbean;
      
          @Autowired
          public ABean(@Value("leesmall") String name, @Qualifier("cbean01") CBean cb) {
              super();
              this.name = name;
              this.cb = cb;
              System.out.println("調用了含有CBean參數的構造方法");
          }
      
          public ABean(String name, CCBean cb) {
              super();
              this.name = name;
              this.cb = cb;
              System.out.println("調用了含有CCBean參數的構造方法");
          }
      
          public ABean(CBean cb) {
              super();
              this.cb = cb;
          }
      }

      Java-based容器配置方式:

      @Configuration
      public class AppConfig {
      
          @Bean
          public MyService myService() {
              return new MyServiceImpl();
          }
      
      }

      上面的AppConfig類等價于:

      <beans>
          <bean id="myService" class="com.acme.services.MyServiceImpl"/>
      </beans>

      想了解java容器配置的朋友請看這篇文章:

      Spring Java-based容器配置

      2.2 IOC容器加載bean定義

      用戶以上面的三種方式配置bean定義以后,Spring IOC容器怎么來加載用戶的bean定義呢,這就需要我們來告訴它了

      xml的方式告訴Spring IOC容器怎么加載bean定義:

              //類路徑下加載xml配置文件創建bean定義
              ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
      
              //文件系統下加載xml配置文件創建bean定義
              ApplicationContext context1 = new FileSystemXmlApplicationContext("e:/study/application.xml");
      
              //通用的xml方式加載xml配置文件創建bean定義
              ApplicationContext context3 = new GenericXmlApplicationContext("file:e:/study/application.xml");

      注解方式告訴Spring IOC容器怎么加載bean定義

      xml方式指定注解要掃描的基礎包:

          <beans>
              <context:component-scan base-package="com.study" />
          </beans>

      注解方式指定注解要掃描的基礎包:

      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      
      @Configuration
      @ComponentScan(basePackages="com.study")
      public class AppConfig {
      
          @Bean
          public MyService myService() {
              return new MyServiceImpl();
          }
      
      }

      也可在代碼中通過API指定注解掃描的基礎包:

              // 掃描注解的方式創建bean定義
              ApplicationContext ctx= new AnnotationConfigApplicationContext();
              ctx.scan("com.study");
              ctx.refresh();
              MyService myService = ctx.getBean(MyService.class);

      Java-based容器配置告訴Spring IOC容器怎么加載bean定義

      使用AnnotationConfigApplicationContext告訴Spring IOC容器怎么加載bean定義配置

      跟實例化一個ClassPathXmlApplicationContext時將Spring XML文件用作輸入相似,在實例化一個AnnotationConfigApplicationContext時能夠使用@Configuration類作為輸入。這就等等于Spring容器全然零XML配置:

      public static void main(String[] args) {
          ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
          MyService myService = ctx.getBean(MyService.class);
          myService.doStuff();
      }

      AnnotationConfigApplicationContext不局限于僅僅使用@Configuration類。不論什么@Component或JSR-330注解的類都能夠作為AnnotationConfigApplicationContext構造器的輸入:

      public static void main(String[] args) {
          ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class);
          MyService myService = ctx.getBean(MyService.class);
          myService.doStuff();
      }

      使用無參的構造器實例化AnnotationConfigApplicationContext,然后使用register()方法對容器進行配置。這樣的方式在以編程方式構造一個AnnotationConfigApplicationContext時非常實用:

      public static void main(String[] args) {
          ApplicationContext ctx = new AnnotationConfigApplicationContext();
          ctx.register(AppConfig.class, OtherConfig.class);
          ctx.register(AdditionalConfig.class);
          ctx.refresh();
          MyService myService = ctx.getBean(MyService.class);
          myService.doStuff();
      }

      啟用scan(String…?)的組件掃描:

      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      
      @Configuration
      @ComponentScan(basePackages="com.study")
      public class AppConfig {
      
          @Bean
          public MyService myService() {
              return new MyServiceImpl();
          }
      
      }

      scan方法掃描:

      public static void main(String[] args) {
          ApplicationContext ctx = new AnnotationConfigApplicationContext();
          ctx.scan("com.study");
          ctx.refresh();
          MyService myService = ctx.getBean(MyService.class);
      }

       二、搞明白Spring IOC的從整體到部分

       

      IOC整體是由以上幾部分組成起來工作的

      三、找到Spring IOC入口,先理清楚主干流程,然后再去研究各個流程的細節

       我們從上面的使用示例,很清楚地看到,我們使用Spring  IOC,只需要使用Spring提供的ApplicationContext這個API。ApplicationContext就是IOC容器。ApplicationContext就是Spring IOC的入口,源碼的學習就從它開始!

       1. ApplicationContext是什么

       首先來了解ApplicationContext都是什么,即它都有哪些角色、責任。它通過繼承很多接口而有很多角色。

      ApplicationContext繼承的接口(角色)如下:

       

      每個角色擁有的職責(方法):

       

      再來了解 ApplicationContext 自己中定義的方法:

       

      2. Application的子實現

       

      說明:

      從 AbstarctApplicationContext 之后分為兩類:xml 配置方式的實現和通用實現。它們的基本使用示例如下:

      package com.study.leesmall.spring;
      
      import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.annotation.AnnotationConfigApplicationContext;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      import org.springframework.context.support.FileSystemXmlApplicationContext;
      import org.springframework.context.support.GenericApplicationContext;
      import org.springframework.context.support.GenericXmlApplicationContext;
      
      import com.study.leesmall.spring.service.Abean;
      import com.study.leesmall.spring.service.CombatService;
      
      //Spring不同的方式創建bean實例使用代碼示例
      @Configuration
      public class TestApplication {
      
          public static void main(String[] args) {
      
              //類路徑下加載xml配置文件創建bean定義
              ApplicationContext context1 = new ClassPathXmlApplicationContext("application.xml");
              CombatService cs = context1.getBean(CombatService.class);
              cs.doInit();
              cs.combating();
      
              //文件系統下加載xml配置文件創建bean定義
              ApplicationContext context2 = new FileSystemXmlApplicationContext("e:/study/application.xml");
              cs = context2.getBean(CombatService.class);
              cs.doInit();
              cs.combating();
      
              //通用的xml方式加載xml配置文件創建bean定義
              ApplicationContext context3 = new GenericXmlApplicationContext("file:e:/study/application.xml");
              cs = context3.getBean(CombatService.class);
              cs.doInit();
              cs.combating();
      
              // 掃描注解的方式創建bean定義
              ApplicationContext context4 = new AnnotationConfigApplicationContext(TestApplication.class);
              CombatService cs2 = context4.getBean(CombatService.class);
              cs2.combating();
              
              //通用的方式加載xml配置文件或者掃描指定包下的類創建bean定義
              System.out.println("------------------------------------------------------");
              GenericApplicationContext context5 = new GenericApplicationContext();
              new XmlBeanDefinitionReader(context5).loadBeanDefinitions("classpath:application.xml");
              new ClassPathBeanDefinitionScanner(context5).scan("com.study.leesmall.spring.service");
              // 一定要刷新
              context5.refresh();
              cs2 = context5.getBean(CombatService.class);
              cs2.combating();
              Abean ab = context5.getBean(Abean.class);
              ab.doSomething();
          }
      
          @Bean
          public CombatService getCombatService() {
              return new CombatService(120);
          }
      }

      接下來,可以打開每個子去了解它們分別加入了什么、實現了什么?

      1)ConfigurableApplicationContext 加入了什么:

       

      說明:

      void addApplicationListener(ApplicationListener<?> listener):這個方法添加監聽 在這里可以進行發布訂閱監聽的工作
      void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor):這個方法可以對bean工廠進行獲取前后的AOP增強
      void refresh() throws BeansException, IllegalStateException:這個方法是用來刷新IOC容器的,當往IOC容器里面注冊了新的Bean定義時,調用這個方法去創建bean實例

      2)AbstractApplicationContext里面對前面的接口就開始有具體的實現了,比如addApplicationListener、addBeanFactoryPostProcessor、refresh等等

      3)通用的實現GenericApplicationContext

      public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
      
          private final DefaultListableBeanFactory beanFactory;
      
          @Nullable
          private ResourceLoader resourceLoader;
      
          private boolean customClassLoader = false;
      
          private final AtomicBoolean refreshed = new AtomicBoolean();

      它實現了BeanDefinitionRegistry接口,該接口定義了bean定義信息的注冊行為。即我們可以直接往GenericApplicationContext中注冊bean定義。
      了解一下BeanDefinitionRegistry中定義的行為:

       

      都有誰實現了 BeanDefinitionRegistry 接口:

       

      GenericApplicationContext中持有DefaultListableBeanFactory,GenericApplicationContext的bean定義注冊委托給了持有的DefaultListableBeanFactory

       

      org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(String, BeanDefinition)對應代碼:

          @Override
          public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
                  throws BeanDefinitionStoreException {
      
              Assert.hasText(beanName, "Bean name must not be empty");
              Assert.notNull(beanDefinition, "BeanDefinition must not be null");
      
              if (beanDefinition instanceof AbstractBeanDefinition) {
                  try {
                      ((AbstractBeanDefinition) beanDefinition).validate();
                  }
                  catch (BeanDefinitionValidationException ex) {
                      throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                              "Validation of bean definition failed", ex);
                  }
              }
      
              BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
              if (existingDefinition != null) {
                  if (!isAllowBeanDefinitionOverriding()) {
                      throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
                  }
                  else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                      // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                      if (logger.isInfoEnabled()) {
                          logger.info("Overriding user-defined bean definition for bean '" + beanName +
                                  "' with a framework-generated bean definition: replacing [" +
                                  existingDefinition + "] with [" + beanDefinition + "]");
                      }
                  }
                  else if (!beanDefinition.equals(existingDefinition)) {
                      if (logger.isDebugEnabled()) {
                          logger.debug("Overriding bean definition for bean '" + beanName +
                                  "' with a different definition: replacing [" + existingDefinition +
                                  "] with [" + beanDefinition + "]");
                      }
                  }
                  else {
                      if (logger.isTraceEnabled()) {
                          logger.trace("Overriding bean definition for bean '" + beanName +
                                  "' with an equivalent definition: replacing [" + existingDefinition +
                                  "] with [" + beanDefinition + "]");
                      }
                  }
                  this.beanDefinitionMap.put(beanName, beanDefinition);
              }
              else {
                  if (hasBeanCreationStarted()) {
                      // Cannot modify startup-time collection elements anymore (for stable iteration)
                      synchronized (this.beanDefinitionMap) {
                          this.beanDefinitionMap.put(beanName, beanDefinition);
                          List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                          updatedDefinitions.addAll(this.beanDefinitionNames);
                          updatedDefinitions.add(beanName);
                          this.beanDefinitionNames = updatedDefinitions;
                          if (this.manualSingletonNames.contains(beanName)) {
                              Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
                              updatedSingletons.remove(beanName);
                              this.manualSingletonNames = updatedSingletons;
                          }
                      }
                  }
                  else {
                      // Still in startup registration phase
                      this.beanDefinitionMap.put(beanName, beanDefinition);
                      this.beanDefinitionNames.add(beanName);
                      this.manualSingletonNames.remove(beanName);
                  }
                  this.frozenBeanDefinitionNames = null;
              }
      
              if (existingDefinition != null || containsSingleton(beanName)) {
                  resetBeanDefinition(beanName);
              }
          }
      View Code

      接下來看GenericApplicationContext的兩個子AnnotationConfigApplicationContext和GenericXmlApplicationContext:

      AnnotationConfigApplicationContext:

      了解它的構造方法、register 方法

      構造方法:

          /**
           * Create a new AnnotationConfigApplicationContext that needs to be populated
           * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
           */
          public AnnotationConfigApplicationContext() {
              this.reader = new AnnotatedBeanDefinitionReader(this);
              this.scanner = new ClassPathBeanDefinitionScanner(this);
          }
      
          /**
           * Create a new AnnotationConfigApplicationContext with the given DefaultListableBeanFactory.
           * @param beanFactory the DefaultListableBeanFactory instance to use for this context
           */
          public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
              super(beanFactory);
              this.reader = new AnnotatedBeanDefinitionReader(this);
              this.scanner = new ClassPathBeanDefinitionScanner(this);
          }
      
          /**
           * Create a new AnnotationConfigApplicationContext, deriving bean definitions
           * from the given annotated classes and automatically refreshing the context.
           * @param annotatedClasses one or more annotated classes,
           * e.g. {@link Configuration @Configuration} classes
           */
          public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
              this();
              register(annotatedClasses);
              refresh();
          }
      
          /**
           * Create a new AnnotationConfigApplicationContext, scanning for bean definitions
           * in the given packages and automatically refreshing the context.
           * @param basePackages the packages to check for annotated classes
           */
          public AnnotationConfigApplicationContext(String... basePackages) {
              this();
              scan(basePackages);
              refresh();
          }

       從構造函數可以看到要完成注解的掃描是通過注解bean定義讀取器AnnotatedBeanDefinitionReader和掃描器ClassPathBeanDefinitionScanner完成的

      GenericXmlApplicationContext :

      了解它的構造方法、load 方法

      構造方法:

          /**
           * Create a new GenericXmlApplicationContext that needs to be
           * {@link #load loaded} and then manually {@link #refresh refreshed}.
           */
          public GenericXmlApplicationContext() {
          }
      
          /**
           * Create a new GenericXmlApplicationContext, loading bean definitions
           * from the given resources and automatically refreshing the context.
           * @param resources the resources to load from
           */
          public GenericXmlApplicationContext(Resource... resources) {
              load(resources);
              refresh();
          }
      
          /**
           * Create a new GenericXmlApplicationContext, loading bean definitions
           * from the given resource locations and automatically refreshing the context.
           * @param resourceLocations the resources to load from
           */
          public GenericXmlApplicationContext(String... resourceLocations) {
              load(resourceLocations);
              refresh();
          }
      
          /**
           * Create a new GenericXmlApplicationContext, loading bean definitions
           * from the given resource locations and automatically refreshing the context.
           * @param relativeClass class whose package will be used as a prefix when
           * loading each specified resource name
           * @param resourceNames relatively-qualified names of resources to load
           */
          public GenericXmlApplicationContext(Class<?> relativeClass, String... resourceNames) {
              load(relativeClass, resourceNames);
              refresh();
          }

       從構造函數可以看出GenericXmlApplicationContext 能從不同的輸入中加載bean定義

      四、細節分析

      從前面的分析,已經對Spring IOC的整體由哪些部分組成有一個了解了,下面就深入去分析各個部分是怎么實現的

      1. Bean定義加載和解析

      ApplicationContext如何加載、解析Bean定義的。讀源碼,我們不光是了解一下這個過程,更重要的是看它是如何設計接口、類來配合解決這個問題的,以及有哪些擴展點、靈活之處。

      1.1 xml文件的bean配置的加載和解析

       xml配置方式的bean定義獲取過程:

      首先,你自己一定要思考清楚這個。然后才去看源碼,不然你都不知道它在干嘛。
      第一次來學習spring的源碼,該怎么來看源碼呢?
        一行一行看,理解每一行?這肯定行不通。
      對于未知的代碼,我們并不清楚它的接口、類結構,方法設計。那怎么看呢?
        首先找準一個你熟悉的過程點,比如上面的過程中,我們比較熟悉xml解析,那xml解析的代碼你是可以看懂的。
        然后以debug的方式開啟發現之旅,從入口處開始一步一步往里跟,直到看到找準的點的代碼。這時一定要記住這個點在哪個類中。下次就可以直接在這里打斷點了。然后要把一路跟過來的調用棧截圖存下來。這個調用棧將是我們重要的分析作者是如何設計接口、類的源泉。
      第一次總是困難的,但之后就輕松了

      開始吧,從這里出發,斷點這行,調試運行

      ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");

       通過艱辛之旅,我們得到了調用棧:

       在這里我們也可以有捷徑獲得這個調用棧,如果你夠細心,會聯想:

      我們知道IOC容器的工作過程是加載xml、解析xml得到bean定義、把bean定義注冊到bean工廠里面、bean工廠根據bean定義創建bean實例,最終目的是注冊bean定義到bean工廠創建bean實例,那么我們就根據ClassPathXmlApplicationContext的繼承體系先找到哪個類里面持有bean工廠,找到持有bean工廠的地方以后先看有沒有注冊bean定義相關的方法,根據繼承體系尋找,最終發現在父類AbstractRefreshableApplicationContext里面持有Bean工廠DefaultListableBeanFactory:

          /** Bean factory for this context. */
          @Nullable
          private DefaultListableBeanFactory beanFactory;

       通過在AbstractRefreshableApplicationContext里面查找,沒有找到注冊bean定義相關的方法,那么我們就看DefaultListableBeanFactory的里面有沒有注冊bean定義相關的方法,最終發現DefaultListableBeanFactory里面果然有注冊bean定義的方法registerBeanDefinition

          @Override
          public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
                  throws BeanDefinitionStoreException {

       通過查看DefaultListableBeanFactory繼承體系,我們可以看到DefaultListableBeanFactory實現了BeanDefinitionRegistry這個接口來實現bean定義注冊

      那么我們就在registerBeanDefinition(String beanName, BeanDefinition beanDefinition)方法里面打個斷點,然后debug運行前面的示例代碼到這里:

      這樣我們就能快速的拿到整個調用棧,而不用一步一步的去debug代碼了:

      那么怎么來具體分析調用棧呢?

      主要看調用棧(看從開始到注冊bean定義這件事情)用到了哪些類的哪些方法,看傳參。工作是如何分配、分工協作完成的。
      看傳參重點是看輸入的參數(如xml配置文件的路徑)在這些類中是怎么變化的(代碼的本質其實就是對輸入數據的各種處理得到最終想要的結果),從而知道每一個類是干什么用的。分析完整個調用棧以后,想要了解哪一部分就點擊對應的調用棧去分析就行了。

      從調用棧可以看到要加載xml、解析xml獲取bean定義、注冊bean定義到bean工廠這些事由以下4個部分組成:

      說明:

      方法里面含有<init>的表示是在構造函數進行初始化,方法里面帶有(AbstractApplicationContext).refresh()的表示調用的是AbstractApplicationContext父類的refresh()方法,其他的類似

      從方法和參數上我們可以看出這4部分分別是做什么:
      第一部分:初始化IOC容器,創建了內部的BeanFactory,然后將加載xml的工作委托給了XmlBeanDefinitionReader。
      第二部分:XmlBeanDefinitionReader完成了對輸入數據:字符串——>Resource——>EncodedResource——>InputSource——>Document的轉變。
      第三部分:DefaultBeanDefinitionDocumentReader完成對Document中元素的解析,獲得Bean定義等信息。
      第四部分:就是簡單的完成bean定義的注冊。

      接下來,你就可以針對每一部分去看你感興趣的處理邏輯、數據結構了。
      比如:你可能對第三部分Document中元素的解析很感興趣,想搞清楚它是如何解析xml文檔中的各種標簽元素的。

      1.1.1 xml元素的解析

       從第三部分的調用棧上,我們可以看到如下變化:

      1——>2 :Document ——>Element

       

      看 doRegisterBeanDefinitions 方法:

       

       

       

      接下來看在 parseBeanDefinitions 方法中是如何來處理里面<beans>的元素的:

      至于它是如何解析bean的不重要,很簡單的。我們重點關心的是它是如何處理其他名稱空間元素的,因為這里是個變化點:其他模塊所需要的標簽各異,表示的信息也不同,它也不知道其他模塊會有哪些標簽。
      它是如何做到以不變應萬變的?看下面的xml配置示例:

       

      就來看 parseCustomElement方法:

      先來看一下 NamespaceHandler 的繼承體系:

       

      NamespaceHandler 里面定義的方法:

      請詳細看NamespaceHandler的接口注釋,方法注釋說明了方法的用法。

       問題:名稱空間對應的處理器在不同的模塊實現,這里是如何加載到的?如事務處理的根本就不在現在的這里。那就要去看圖中的這條語句的方法調用了:

       進入resolve 方法

       

      它是一個接口,那這里用的是它的什么實現類對象呢?

       

       我們看到有兩個屬性classLoader,handlerMappingsLocation。從handlerMappingsLocation這個名字能知道這是處理器與名稱空間的映射的配置所在的地址。從前兩個構造方法,我們看到它給入了一個常量的地址值:

       

      可大膽推測它是要到類目錄下去找這個文件??聪挛覀兊?spring 的模塊 jar 包下有沒有這個文件

       

       

       

      接下來來看下 resolve 方法:

       

       

      請把NamespaceHandler、NamespaceHandlerResolver的類圖畫出來。思考一下這里有用到什么設計原則、設計模式?【很重要】

       

      擴展:
      1)如果你需要加一個自己開發的模塊(含自定義的bean定義標簽)到spring中,你是否可以做到了。

      請看我的文章:

      dubbo系列三:dubbo源碼分析(dubbo框架是如何跟spring進行整合的,消費者獲取的代理實例是如何創建的呢、生產者怎么把內容注冊到注冊中心的,然后消費者是如何獲取這個信息的、dubbo負載均衡策略)

      中的dubbo框架是如何跟spring進行整合的

      2)spring標簽處理這里的設計:模塊之間可以靈活組合,配置在各自的模塊中,即插即用。你是否可以把它應用到你的系統設計上。

         策略模式跟工廠模式的組合使用

       那么通用的實現 GenericXmlApplicationContext 加載xml、獲取bean定義、注冊bean定義的調用棧是否也是一樣的呢?

      ClassPathXmlApplicationContext加載xml、獲取bean定義、注冊bean定義:

              //類路徑下加載xml配置文件創建bean定義
              ApplicationContext context1 = new ClassPathXmlApplicationContext("application.xml");

       斷點在DefaultListableBeanFactory中的注冊方法上:

      GenericXmlApplicationContext 加載xml、獲取bean定義、注冊bean定義:

              //通用的xml方式加載xml配置文件創建bean定義
              ApplicationContext context3 = new GenericXmlApplicationContext("file:e:/study/application.xml");

       斷點還是在DefaultListableBeanFactory中的注冊方法上:

      經過對比:

      ClassPathXmlApplicationContext和GenericXmlApplicationContext 加載xml、獲取bean定義、注冊bean定義的過程是一樣的

      1.2  bean工廠DefaultListableBeanFactory

       經過前面的分析,我們發現bean定義都是注冊到DefaultListableBeanFactory中。接下來就來認識一下它

       在ApplicationContext的兩類實現中,通過查看繼承體系我們都可以看到ApplicationContext中持有DefaultListableBeanFactory:

       

       xml配置方式的實現的父類:

       

      通用實現:

      下面我們來看一下ApplicationContext和BeaFatory的關系

       

      1.3 注解方式的bean配置的加載和解析

       入口:

              // 掃描注解的方式創建bean定義
              AnnotationConfigApplicationContext context4 = new AnnotationConfigApplicationContext("com.study.leesmall.spring.service");

      斷點還是在DefaultListableBeanFactory中的注冊方法上:

       

      debug到上面的斷點以后拿到的調用棧:

      在這個調用棧中,我們并發沒有看到它做包掃描的相關工作。從下往上看這個執行棧,點第2個執行??创a:

       

      它現在是在做一些初始化的準備處理,從這里我們獲知,它做了registerAnnotationConfigProcessors。從名字上理解就是注冊了一些注解配置的處理器。到底是一些什么processors,點方法進去看看:

       

       

       

      注冊各種processor

      它注冊了很多的processor,都是些什么Processor?點第一個的類名進去看看

       

       BeanDefinitionRegistryPostProcessor擴展了BeanFactoryPostProcessor,增加了BeanDefinitionRegistry位置的處理,即它可以提前對注冊好的BeanDefinitionRegistry進行前置處理。

       下面我們來看一下BeanFactoryPostProcessor:

       

      來看看BeanFactoryPostProcessor有哪些實現:

      這是springIOC中給我們提供的又一個【擴展點】,讓我們可以在beanFactory開始創建Bean實例前對beanFactory進行一些處理?。?!

      使用示例如下:

          <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
              <property name="locations" value="classpath:application.properties"/>
          </bean>

       擴展一個自己的BeanFactoryPostProcessor:

      package com.study.leesamll.spring.ext;
      
      import org.springframework.beans.BeansException;
      import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
      import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
      import org.springframework.stereotype.Component;
      
      @Component
      public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
      
          @Override
          public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
              System.out.println(this + "  擴展一個自己的BeanFactoryPostProcessor");
          }
      
      }

      入口:

              // 掃描注解的方式創建bean定義
              AnnotationConfigApplicationContext context4 = new AnnotationConfigApplicationContext("com.study.mike.spring.service");
              context4.close();

       BeanFactoryPostProcessor的類圖

       

      1.3.1 掃描包獲取bean定義的過程是怎樣的?

       前面我們分析到,注解方式是在scan方法開始進行掃描的

      那么我們就在這個方法的這里再打個斷點,記住之前的bean工廠注冊方法里面的斷點保留,debug調試看一下調用棧

      從調用棧上我們可看到有哪些類參與進來,在哪里發生的什么。

       下面來看一下是怎么掃描的:

       

       

      下面來看一下掃描候選組件的方法:

       

       類圖如下:

       

      參考文章:

      Spring Java-based容器配置

      完整代碼獲取地址:https://github.com/leeSmall/FrameSourceCodeStudy/tree/master/spring-source-study

      posted @ 2019-03-17 10:48  小不點啊  閱讀(1561)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 无码AV中文字幕久久专区 | аⅴ天堂中文在线网| 亚洲区激情区无码区日韩区 | 成人免费无码大片A毛片抽搐色欲| 国产乱子伦视频在线播放| 国产福利在线观看免费第一福利| 又湿又紧又大又爽A视频男| 成人精品自拍视频免费看| 久久99精品中文字幕在| 国模肉肉视频一区二区三区| 日韩中文字幕av有码| 日本成人午夜一区二区三区| 国产熟睡乱子伦视频在线播放| 色欲av无码一区二区人妻| 99精品日本二区留学生| 东京热人妻丝袜无码AV一二三区观| 强d乱码中文字幕熟女1000部| 日本一码二码三码的区分| 最近中文字幕完整版hd| 国产一区二区三区小说| 亚洲成a人v欧美综合天堂下载| 老熟妇欲乱一区二区三区| 国产免费高清69式视频在线观看| 中国CHINA体内裑精亚洲日本| 中文国产不卡一区二区| 国产成人A在线视频免费| 国产欧亚州美日韩综合区| 亚洲区综合区小说区激情区| 成av人电影在线观看| 国产成人免费ā片在线观看| 我要看特黄特黄的亚洲黄片| 成人做受120秒试看试看视频| jizz视频在线观看| A毛片终身免费观看网站| 丁香五月激情综合色婷婷| 亚洲第一二三区日韩国产| 国内精品视频区在线2021| 亚洲成a人片在线观看中| 国产亚洲精品aaaa片app| 国产99久久精品一区二区| 国产一区日韩二区欧美三区|