Spring Boot启动流程源码解析

定义:

BeanFactoryPostProcessor:是一个接口,它允许自定义修改应用程序上下文的beanDefiinition

BeanDefinitionRegistryPostProcessor:是一个接口,继承接口BeanFactoryPostProcessor,该接口新增postProcessBeanDefinitionRegistry方法,方法参数是 BeanDefinitionRegistry对象,BeanDefinitionRegistry对象是beanDefiinition的保存中心

BeanPostProcessor:在bean实例化的时候,进行切面处理,在实例化的前执行postProcessBeforeInitialization,在实例化后执行postProcessAfterInitialization

一、SpringApllication实例化,进行初始化操作:

它调用getSpringFactoriesInstances(Bootstrapper.class),在多个应用的META-INF/spring.factories文件下获取,key=Bootstrapper的启动类加载器的包路径,并通过class.forName反射,然后把实例放到集合进行Order排序,设置优先级,返回集合。

但是此处,由于META-INF/spring.factories文件没有key=Bootstrapper的信息,故返回了一个空集合。

getSpringFactoriesInstances(ApplicationContextInitializer.class))的作用:在多个应用的META-INF/spring.factories文件下获取,key=ApplicationContextInitializer初始化器的包路径,并通过class.forName反射,然后把实例放到集合进行Order排序,设置优先级,返回集合,并通过setInitializers对本对象属性initializers(初始化器)进行赋值。 初始化器,在spring容器刷新之前,进行接口回调initialize方法

返回的初始化器如下:

getSpringFactoriesInstances(ApplicationListener.class)的作用:在多个应用的META-INF/spring.factories文件下获取,key=ApplicationListener初始化器的包路径,并通过class.forName反射,然后把实例放到集合进行Order排序,设置优先级,返回集合,并通过setListeners对本对象属性listeners(监听器)进行赋值。

返回的监听器如下:

【1】创建临时上下文

【2】配置系统硬件属性

【3】获取监听器并启动:getRunListeners(args)

在META-INF/spring.factories文件下获取key= SpringApplicationRunListener的类路径获得org.springframework.boot.context.event. EventPublishingRunListener

并通过class.forName反射实例化返回 instances,然后通过new SpringApplicationRunListeners( log, instances, applicationStartup),把EventPublishingRunListener封装到SpringApplicationRunListeners的List集合里。

SpringApplicationRunListener负责在SpringBoot启动的不同阶段,使用内部ApplicationEventMulticaster来广播不同的SpringApplicationEven事件,传递给前面的ApplicatioinListener监听器实现类。比如,”刷新上下文准备阶段” 完成了,就向各个SpringApplicationListener监听器发布”刷新上下文准备阶段” 事件,让各个监听器此时执行对应的逻辑。

【4】准备容器环境:prepareEnvironment

上下文环境本质上就是环境信息的集合:系统变量、环境变量、JDK环境信息、命令行参数,默认变量,servlet相关配置变量,随机值、JNDI属性值,以及配置文件(比如application.properties)等。

这些环境变量是有优先级的。对这些信息加载进来,封装到environment对象中。

发布事件

具体prepareEnvironment方法:

根据webApplicationType实例化不同的环境类:

SERVLET -> new ApplicationServletEnvironment()

REACTIVE -> new ApplicationReactiveWebEnvironment()

other -> new ApplicationEnvironment()

【6】创建上下文和容器:createApplicationContext()

根据webApplicationType实例化不同的上下文ConfigurableApplicationContext实现类:

SERVLET -> new AnnotationConfigServletWebServerApplicationContext()

REACTIVE -> new AnnotationConfigReactiveWebServerApplicationContext()

other ->new AnnotationConfigApplicationContext()

于此同时,因为这几个实现类,继承了GenericApplicationContext,而GenericApplicationContext的构造函数中会创建beanFactory,故子类实例化,父类GenericApplicationContext也会跟着实例化,beanFactory其实际上就是IOC容器,类型为DefaultListableBeanFactory,即上下文中有了一个IOC容器

【7】刷新上下文准备阶段prepareContext

【8】刷新上下文:refreshContext(context)

刷新之前,会在context上下文添加一个ApplicationContextClosedListener监听,就是为了在shutdown的时候,优雅的关闭应用。

刷新的核心代码如下:

beanFactory初始化的值:

  1. 设置类加载器 :setBeanClassLoader

2.设置Spel表达式的解析器 :setBeanExpressionResolver

3.添加属性编辑器 :addPropertyEditorRegistrar 添加属性编辑器

4.添加Bean后置处理器:addBeanPostProcessor

5.设置忽略指定类的自动装配功能:ignoreDependencyInterface

6.自动装配是,指定对应接口的注入对象(一个接口可有多个对象):registerResolvableDependency

7.设置单例:registerSingleton

1.设置request、session作用域的注入对象

2.设置自动装配时接口注入指定对象

该方法顾名思义,就是调用Bean定义注册后处理器,形参:

currentRegistryProcessors :BeanDefinition注册后处理器集合,就一个ConfigurationClassPostProcessor类处理器

registry:BeanDefinition的注册中心,本质是就是IOC容器里有该注册中心Map

applicationStartup:记录器,用于记录程序执行

该处理器为类型ConfigurationClassPostProcessor,是接口BeanDefinitionRegistryPostProcessor的实现类,如实现类:

CachingMetadataReaderFactoryPostProcessor.postProcessBeanDefinitionRegistry:是把beanDefinition注册到容器中;

ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry:是处理有注解的beanDefinition,该方法实现逻辑:

一、在beanDefinition容器中,通过判断是否包含注解@component,拿到启动类

二、通过ConfigurationClassParser.parser解析

1:先解析到@SpringBootApplication,把启动类的beanDefinition封装成SourceClass,被用来更直接检测包含哪些注解的一个类

2:通过递归处理内部类,把有注解的类记录下来

3:解析标注@PropertySource的类,处理类成员的值

4:解析标注@ComponentScan的类,检测到启动类,在启动类所在包及子包进行扫描,直接或间接标注@component的类,都会被扫描到,并把对应类的beanDefinition注册到容器中,然后 递归调用ConfigurationClassParser.parser进行解析。

5:解析标注@Import的类,递归解析自身和父注解的@import,解析到@import.value=ImportBeanDefinitionRegistrar 进行记录;解析到@import.value=ImportSelector进行记录,并通过调用selectImports方法把扫描配置文件META-INF/spring.factories,把里面的类扫描,并检测这类是否有注解,如果有,则也需要 递归调用ConfigurationClassParser.parser进行解析

经过这一系列解析,就通过注解拿到了全部需要实例化注入到IOC容器的类

注册方式: PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, applicationContent);

比如:国际化

1.初始化主题来源ThemeSource

2.构造TomcatServletWebServer,并初始化server的配置,并注入到IOC容器中

拿到容器中的beanDefinition集合,结合bean后置处理器进行实例化,并注入到IOC容器中

1.设置管理bean生命周期的LifecycleProcessor处理器

2.用LifecycleProcessor开始webServerGracefulShutdown、webServerStartStop两个Group 的生命周期管理

3.发布”容器刷新完成”事件

4.为MBeanServer注册LiveBeansView

【9】刷新上下文后操作:afterRefresh,空方法

【10】发布”容器加载完成”事件给监听器:listeners.started

【11】启动Spring的Runner加载容器启动后数据

Original: https://www.cnblogs.com/incognitor/p/16049092.html
Author: 無名之徒
Title: Spring Boot启动流程源码解析

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/621524/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球