SpringBoot 启动分析 序列文章基于 spring-boot-starter-parent 1.5.19.RELEASE 。
1. 启动一个 SpringBoot 应用
启动一个 SpringBoot 应用只需要下面几行代码即可:
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
查看 SpringApplication.run
方法时会来到:
public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
}
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
可以看到 SpringBoot 的魔法就是那么简单:创建一个 SpringApplication,执行其 run 方法。
就像 “打开冰箱门、把大象塞进冰箱、关上冰箱门” 那么简单、有力。
当然,要了解原理是不能只看高层抽象的。
2. SPI 机制 SpringFactoriesLoader
SpringFactoriesLoader 是 Spring 提供的 SPI 实现机制,从类路径下的 META-INF/spring.factories
文件里加载指定接口的所有实现。以接口的完整类名作为 key,实现类的完整名字作为值,多个实现类用 ,
分隔。
下面是 spring-boot-autoconfigure 包下 META-INF/spring.factories
文件里的 一小部分:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.cloud.CloudAutoConfiguration,\
SpringFactoriesLoader 内部通过 ClassLoader.getResources
方法来加载类路径下的文件。
3. 事件与监听器
SpringBoot 利用事件与监听器来简化启动主流程的逻辑。
-
SpringApplicationRunListeners
:持有一组SpringApplicationRunListener
的引用,用于批量通知SpringApplicationRunListener
。 -
SpringApplicationRunListener
:用于监听SpringApplication
.run
方法的执行,有5个回调方法:started
:run方法执行的时候立马执行;对应事件的类型是ApplicationStartedEvent
。environmentPrepared
:ApplicationContext
创建之前并且环境信息准备好的时候调用;对应事件的类型是ApplicationEnvironmentPreparedEvent
。contextPrepared
:ApplicationContext
创建好并且在source加载之前调用一次;没有具体的对应事件。contextLoaded
:ApplicationContext
创建并加载之后并在refresh之前调用;对应事件的类型是ApplicationPreparedEvent
。finished
:run方法结束之前调用;对应事件的类型是ApplicationReadyEvent
或ApplicationFailedEvent
。
-
ApplicationListener
:应用事件监听器。 -
事件广播关系:
SpringApplicationRunListeners -->
SpringApplicationRunListener(EventPublishingRunListener) --> ApplicationEventMulticaster(SimpleApplicationEventMulticaster) -->
ApplicationListener
4. ApplicationContext 的重要组件及扩展机制,
下面是从运行时的角度看ApplicationContext 的重要组件及扩展机制,而非源码组织的角度。
-
Environment
:由下面两个组成。- Profiles:bean和属性的逻辑分组,一般用于表示不同环境下的配置。表示配置的分组一般是用在配置文件名上,比如
application-${profile}.properties
,用在 Bean 上一般是@Profile({"p1", "!p2"})}
表示p1
激活或p2
不激活时启用。一个 Bean 如果没有声明 profile 则表示默认是激活的,配置文件名上不带 profile 信息则表示是默认的配置。 - Properties:配置的键值属性,可以从很多来源进行初始化。一个配置文件的键值对被封装在一个
PropertySource
里,PropertySources
持有一个或多个PropertySource
。
- Profiles:bean和属性的逻辑分组,一般用于表示不同环境下的配置。表示配置的分组一般是用在配置文件名上,比如
-
BeanFactory
:Bean工厂,可以进行 Bean定义注册、实例化 Bean、对外提供获取 Bean 实例的功能。一般还持有一个对父BeanFactory
的引用。当获取一个Bean时,如果当前工厂不存在给定BeanName的Bean定义,则尝试从父BeanFactory
获取。 -
BeanFactoryPostProcessor
:用于定制化修改上下文底层 BeanFactory 里的 Bean 定义和适配 Bean 属性的值。该接口只有一个方法void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
。BeanDefinitionRegistryPostProcessor
继承自
BeanFactoryPostProcessor
,并在BeanFactoryPostProcessor
被应用之前先应用,用于注册更多的 Bean。有一个新增的方法void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
。
-
BeanPostProcessor
:一种扩展机制,包含两个方法,用于对创建的 Bean 进行增强,AOP就是在这个机制实现类里实现的。
Object postProcessBeforeInitialization(Object bean, String beanName)
`Object postProcessAfterInitialization(Object bean, String beanName)
-
EnvironmentPostProcessor
:Environment
后置处理器,由ConfigFileApplicationListener.onApplicationEnvironmentPreparedEvent
触发执行,具体的实现类有:- CloudFoundryVcapEnvironmentPostProcessor
- ConfigFileApplicationListener:用于加载 PropertySources,资源。
- HostInfoEnvironmentPostProcessor
- ServoEnvironmentPostProcessor
- SpringApplicationJsonEnvironmentPostProcessor
-
同一类组件的不同实现的执行顺序是有一定规则的
- A. 不同组件的实现有如下三类分类
-
- 实现 PriorityOrdered 接口
-
- 实现 Ordered 接口
-
- 非继承上述两个接口的
- B. 执行顺序规则
-
- PriorityOrdered -> Ordered -> 非继承上述接口的
-
- 同一类实现的 order 值越低优先级越高
-
ConfigurationClassParser
:它的processConfigurationClass
方法递归地解析@Configuration
配置类,SpringBoot 的 auto-configure 机制就是在这个阶段被解析到上下文里的。- 递归处理所有嵌套类
- 处理源类上
@PropertySource
注解指定的配置文件 - 处理
@ComponentScan
注解 - 处理
@Import
注解 - 处理
@ImportResource
注解 - 处理所有
@Bean
方法 - 处理 interfaces 上的默认方法
- 递归处理父类
-
ConfigurationClassBeanDefinitionReader
:把ConfigurationClassParser
解析得到的 Bean 定义 注册到BeanDefinitionRegistry
。 -
ConfigurationClassPostProcessor
:借助ConfigurationClassParser
和ConfigurationClassParser
递归地解析配置类并注册到BeanDefinitionRegistry
。 -
ConditionEvaluator
:根据@Conditional
注解进行评估一个 Bean 定义是否应该注册。
5. SpringBoot 启动流程概要
- 创建一个
ConfigurableEnvironment
,广播ApplicationEnvironmentPreparedEvent
事件,ConfigFileApplicationListener
收到通知后利用 SPI 机制加载所有EnvironmentPostProcessor
的实现类,触发其postProcessEnvironment
方法。ConfigFileApplicationListener
自身也实现了EnvironmentPostProcessor
接口,在它的postProcessEnvironment
里通过内部类 Loader 加载所有的配置文件,并处理 profile,最终所有键值对都被添加到 Environment 里。 - 实例化一个
AnnotationConfigApplicationContext
,实例化的过程中会把 应用指定的启动配置类、ConfigurationClassPostProcessor
实例注册到底层的 BeanFacotry 实例里。 - 上下文 refresh 过程会触发执行
ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry
注册所有的 Bean 定义。 - 找出上下文里所有非延迟加载的单例的 BeanName,逐个实例化,实例化过程中应用
BeanPostProcessor
进行加工增强,得到最终的 Bean object 给应用使用。
欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。
感谢分享~