码迷,mamicode.com
首页 > 编程语言 > 详细

springboot启动过程(3)-refresh方法

时间:2017-07-10 23:33:28      阅读:598      评论:0      收藏:0      [点我收藏+]

标签:自己   ntp   classpath   项目   准备工作   实现类   port   reset   tee   

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方法。

springboot启动过程(3)-refresh方法

标签:自己   ntp   classpath   项目   准备工作   实现类   port   reset   tee   

原文地址:http://www.cnblogs.com/lkdirk/p/7145941.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!