springboot启动过程-refresh方法

练拳码农      2022-02-13     314

关键词:

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启动流程ioc容器refresh过程(上篇)

所有文章https://www.cnblogs.com/lay2017/p/11478237.html 正文在前面的几篇文章中,我们看到Environment创建、application配置文件的加载、ApplicationContext实例对象的创建、以及主类加载成为BeanDefinition。做了这么多的准备,终于到了核心的... 查看详情

springboot与tomcat的启动(内嵌tomcat)

参考技术A环境:SpringBoot2.0.1使用SpringBoot开发时,可以通过Maven将工程打成jar包,jar包内嵌Tomcat,这种方式SpringBoot工程将在启动的时候,带动Tomcat的启动,下面分析SpringBoot如何带动Tomcat启动一个简单的SpringBoot工程启动类跟进Sprin... 查看详情

记一次启动springboot失败的问题

参考技术A在开发SpringBoot项目的时候,启动项目,启动失败,提示如下,只截取关键部分:该异常的Description只是表面现象,而不是根本原因,要想知道根本原因,就需要查看是否之前就抛出了其他异常。正是更早的异常导致Sprin... 查看详情

springboot的启动过程及部分注解

参考技术A相比于以前繁琐的基于Spring的Web应用,SpringBoot通过默认配置很多框架的方式,极大的简化了项目的搭建以及开发流程。一个简单的SpringBoot应用只需要三步:1.在pom.xml中引入所需要的依赖2.在application.yml配置所需的数据... 查看详情

springboot启动分析

...初始化过程的三个步骤。  第一步:Resource定位  在SpringBoot中,我们都知道他的包扫描是从主类所在的包开始扫描的,prepareContext()方法中,会先将主类解析成BeanDefinition,然后在refresh()方法的invokeBeanFactoryPostProcessors()方法中... 查看详情

springboot启动过程原理

最近这两年springboot突然火起来了,那么我们就来看看springboot的运行原理。一。springboot的三种启动方式:1.运行带有main方法的2.通过命令Java-jar命令3.通过spring-boot-plugin的方式二。springboot启动时执行方法,有两种方式第一种方式... 查看详情

使用 SpringBoot 2 自动化 OAuth2 refresh_token 过程

】使用SpringBoot2自动化OAuth2refresh_token过程【英文标题】:automatetheOAuth2refresh_tokenprocesswithSpringBoot2【发布时间】:2022-01-0203:56:16【问题描述】:我有一个SpringBoot2应用程序,一个作为resource-server的MainApp,作为AuthorizationServer的KeyCloa... 查看详情

涨姿势:springboot2.x启动全过程源码分析

目录SpringApplication实例run方法运行过程总结上篇《SpringBoot2.x启动全过程源码分析(一)入口类剖析》我们分析了SpringBoot入口类SpringApplication的源码,并知道了其构造原理,这篇我们继续往下面分析其核心run方法。SpringApplication实... 查看详情

springboot启动过程:springapplication及springapplicationbuilder

SpringBoot应用的启动是基于SpringApplication类的,下面一步步地分析。构造方法及初始化其构造方法有二,都调用了initialize方法,完成注解源的配置。 publicSpringApplication(Object...sources) initialize(sources); publicSpringApplication(R 查看详情

springboot启动过程-初始化

1 springboot启动时,只需要调用一个类前面加了@SpringBootApplication的main函数,执行SpringApplication.run(DemoApplication.class,args)即可,这里初始化了一个SpringApplication实例,然后调用run启动springboot。run方法中,调用了initialize,如下@Suppr... 查看详情

quartz与spring集成——启动调度器

...动过程。熟悉Spring原理的人都知道AbstractApplicationContext的refresh方法的重要性,在refresh方法中调用了finishRefresh方法,最后会调用到SchedulerFactoryBean的start方法,其调用栈如图1所示。图1 SchedulerFact 查看详情

springboot启动过程

写过SpringBoot都知道需要有一个入口类,这个类上面必不可上的需要有一个@SpringBootApplication注解还有run方法,下面我们讲一下他们。@SpringBootApplication点击进入该注解,我们可以发现其是一个复合注解,包括@SpringBootConfiguration、@En... 查看详情

跟跟springboot启动容器,自动装配的过程

...习------------------------------------------------------------运行被@SpringBootApplication修饰的程序入口,执行main方法,调用SpringAppl 查看详情

springboot启动流程

...法里面new一个SpringApplication对象,传入bean源,就是注解了SpringBootApplication的那个类,调用run方法。springboot启动流程分为两部分一部分是准备阶段,一部分是运行阶段准备阶段主要有这么几步:1、配置bean的源,就是bean的来源,... 查看详情

springboot启动过程:springapplication及springapplicationbuilder(代码片段)

SpringBoot应用的启动是基于SpringApplication类的,下面一步步地分析。构造方法及初始化其构造方法有二,都调用了initialize方法,完成注解源的配置。 publicSpringApplication(Object...sources) initialize(sources); publicSpringApplication(Res... 查看详情

springboot启动过程:springapplication及springapplicationbuilder(代码片段)

SpringBoot应用的启动是基于SpringApplication类的,下面一步步地分析。构造方法及初始化其构造方法有二,都调用了initialize方法,完成注解源的配置。 publicSpringApplication(Object...sources) initialize(sources); publicSpringApplication(Res... 查看详情

springboot启动流程

springboot版本为:2.2.3概述springboot的启动过程主要是两个方面,一个是创建SpringApplication这个类,该类用于启动启动整个应用,是应用的启动类。另一方面是SpringApplication的run方法,该方法会初始化listener和initialize,并在分发事件到... 查看详情

启动springboot报错,怎么解决

【解决办法】需要在启动类的@EnableAutoConfiguration或@SpringBootApplication中添加exclude=DataSourceAutoConfiguration.class,排除此类的autoconfig。启动以后就可以正常运行。【原因】这个原因是maven依赖包冲突,有重复的依赖。【Spring  Boo... 查看详情