springboot啟動過程(3)-refresh方法


1  springboot在啟動的時候,會調用run方法,創建環境設置spring容器,其中包含refresh方法,完成配置類解析,各種beanFactoryPostProcess和beanPostProcessor注冊,web內置容器構造,國際化配置初始化等,refresh調用了父類AbstractApplicationContext的refresh方法如下。

public void refresh() throws BeansException, IllegalStateException {
  Object var1 = this.startupShutdownMonitor;
  synchronized(this.startupShutdownMonitor) {
    this.prepareRefresh();
    ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
    this.prepareBeanFactory(beanFactory);

    try {

      this.postProcessBeanFactory(beanFactory);
      this.invokeBeanFactoryPostProcessors(beanFactory);
      this.registerBeanPostProcessors(beanFactory);
      this.initMessageSource();
      this.initApplicationEventMulticaster();
      this.onRefresh();
      this.registerListeners();
      this.finishBeanFactoryInitialization(beanFactory);
      this.finishRefresh();
    } catch (BeansException var9) {
      if(this.logger.isWarnEnabled()) {
        this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
      }

      this.destroyBeans();
      this.cancelRefresh(var9);
      throw var9;
    } finally {
      this.resetCommonCaches();
    }

  }
}

 (1)prepareRefresh  在rehresh之前做的准備工作,一是設置spring啟動事件,開啟活躍狀態;二是初始化屬性源信息;三是驗證必要屬性。

 (2)prepareBeanFactory  從spring容器獲取BeanFactory並進行相關設置為后續使用做准備。

        *設置用於加載bean的classLoader,設置可以解析bean表達式的表達式解析器,添加屬性注冊器ResourceEditorRegistrar。

        * 添加ApplicationContextAwarePocessor這個BeanPostProcessor,注入ResourceLoaderAware、ApplicationEventPublisherAware、MessageSourceAware、ApplicationContextAware、EnvironmentAware幾個接口。

       * 設置各種bean,BeanFactory,ResourceLoader,ApplicatioinEventPublisher,ApplicationContext。

       * 配置默認系統屬性等。

 (3)postProcessBeanFactory 繼上一步beanfactory設置之后進行后續操作,不同spring容器進行不同操作。比如AnnotationConfigEmbeddedWebApplicationContext會對bean進行注入,檢查basePackages屬性,如果設置了會使用ClassPathBeanDefinitionScanner對basePackage下面的bean進行掃描並注冊,如果設置了annotatedClasses屬性,就會使用AnnotatedBeanDefinitionReader注冊這些帶注解的bean。

 (4)invokeBeanFactoryPostProcessors

       * BeanFactoryPostProcessor   其實現類可以在spring容器加載了bean的定義文件之后,在bean實例化之前執行。接口方法的入參是ConfigurrableListableBeanFactory,使用該參數,可以獲取到相關bean的定義信息,修改各種配置的元數據,可以配置多個processor,通過設置order屬性來控制各個實現類的執行順序。

       * BeanPostProcessor  BeanPostProcessor是在spring容器加載了bean的定義文件並且實例化bean之后執行的。BeanPostProcessor的執行順序是在BeanFactoryPostProcessor之后,BeanPostProcessor的作用域是容器級的,它只和所在容器有關。如果你在容器中定義了BeanPostProcessor,它僅僅對此容器中的bean進行后置。它不會對定義在另一個容器中的bean進行任何處理。

       * BeanDefinitionRegistryPostProcessor:繼承BeanFactoryPostProcessor,作用跟BeanFactoryPostProcessor一樣,只不過是使用BeanDefinitionRegistry對bean進行處理

       基於web程序的Spring容器AnnotationConfigEmbeddedWebApplicationContext構造的時候,會初始化內部屬性AnnotatedBeanDefinitionReader reader,這個reader構造的時候會在BeanFactory中注冊一些post processor,包括BeanPostProcessor和BeanFactoryPostProcessor(比如ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor);invokeBeanFactoryPostProcessors方法處理BeanFactoryPostProcessor的邏輯是:

從Spring容器中找出BeanDefinitionRegistryPostProcessor類型的bean(這些processor是在容器剛創建的時候通過構造AnnotatedBeanDefinitionReader的時候注冊到容器中的),然后按照優先級分別執行,優先級的邏輯如下:

     1)實現PriorityOrdered接口的BeanDefinitionRegistryPostProcessor先全部找出來,然后排序后依次執行

             2)實現Ordered接口的BeanDefinitionRegistryPostProcessor找出來,然后排序后依次執行

     3)沒有實現PriorityOrdered和Ordered接口的BeanDefinitionRegistryPostProcessor找出來執行並依次執行

    ConfigurationClassPostProcessor這個processor是優先級最高的被執行的processor(實現了PriorityOrdered接口)。這個ConfigurationClassPostProcessor會去BeanFactory中找出所有有@Configuration注解的bean,然后使用ConfigurationClassParser去解析這個類。ConfigurationClassParser內部有個Map類型的configurationClasses屬性用於保存解析的類,ConfigurationClass是一個對要解析的配置類的封裝,內部存儲了配置類的注解信息、被@Bean注解修飾的方法、@ImportResource注解修飾的信息、ImportBeanDefinitionRegistrar等都存儲在這個封裝類中。這里ConfigurationClassPostProcessor最先被處理還有另外一個原因是如果程序中有自定義的BeanFactoryPostProcessor,那么這個PostProcessor首先得通過ConfigurationClassPostProcessor被解析出來,然后才能被Spring容器找到並執行。(ConfigurationClassPostProcessor不先執行的話,這個Processor是不會被解析的,不會被解析的話也就不會執行了)。

  invokeBeanFactoryPostProcessors方法總結來說就是從Spring容器中找出BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor接口的實現類並按照一定的規則順序進行執行。 其中ConfigurationClassPostProcessor這個BeanDefinitionRegistryPostProcessor優先級最高,它會對項目中的@Configuration注解修飾的類(@Component、@ComponentScan、@Import、@ImportResource修飾的類也會被處理)進行解析,解析完成之后把這些bean注冊到BeanFactory中。需要注意的是這個時候注冊進來的bean還沒有實例化。

 (5)registerBeanPostProcessors  

  使用了PostProcessorRegistrationDelegate類的registerBeanPostProcessors方法執行。這里的過程跟invokeBeanFactoryPostProcessors類似:
    1)先找出實現了PriorityOrdered接口的BeanPostProcessor並排序后加到BeanFactory的BeanPostProcessor集合中
    2)找出實現了Ordered接口的BeanPostProcessor並排序后加到BeanFactory的BeanPostProcessor集合中
    3)沒有實現PriorityOrdered和Ordered接口的BeanPostProcessor加到BeanFactory的BeanPostProcessor集合中
  這些已經存在的BeanPostProcessor在postProcessBeanFactory方法中已經說明,都是由AnnotationConfigUtils的registerAnnotationConfigProcessors方法注冊的。這些BeanPostProcessor包括有AutowiredAnnotationBeanPostProcessor(處理被@Autowired注解修飾的bean並注入)、RequiredAnnotationBeanPostProcessor(處理被@Required注解修飾的方法)、CommonAnnotationBeanPostProcessor(處理@PreDestroy、@PostConstruct、@Resource等多個注解的作用)等。如果是自定義的BeanPostProcessor,已經被ConfigurationClassPostProcessor注冊到容器內。
  這些BeanPostProcessor會在這個方法內被實例化(通過調用BeanFactory的getBean方法,如果沒有找到實例化的類,就會去實例化)。

 (6)initMessageSource  初始化國際化屬性。

 (7)initApplicationEventMulticaster  初始化事件廣播器,用於發布事件。EventPublishingRunlistener會監聽事件,在run函數之前contextPrepared時候已經注入了。這個時候不需要注冊,只要拿到BeanFactory的廣播器直接設置到spring容器,如果沒有再自己初始化。

 (8)onRefresh  不同容器各自實現,比如ConfigEmbeddedWebApplicationContext中會調用createEmbeddedServletContainer方法去創建內置的Servlet容器,目前只支持三種 tomcat,jetty,undertow。

 (9)registerListeners 把spring容器內的listener和beanfactory的listener都添加到廣播器中。

 (10)finishBeanFactoryInitialization  實例化BeanFactory 中已經被注冊但是沒被實例化的所有實例,懶加載除外。比如invokeBeanFactoryPostProcessors方法中根據各種注解解析出來的類,都會初始化。初始化的過程中各種BeanPostProcessor開始起作用。

 (11)finishRefresh 初始化生命周期處理器LifecycleProcessor並調用其onrefresh方法,找到SmartLifecycle接口的所有實現類並調用start方法,發布事件告知listener,如果設置了JMX相關屬性,還會調用LiveBeansView的registerApplicationContext方法。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM