SpringBoot 启动分析(一)

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
    • environmentPreparedApplicationContext 创建之前并且环境信息准备好的时候调用;对应事件的类型是ApplicationEnvironmentPreparedEvent
    • contextPreparedApplicationContext创建好并且在source加载之前调用一次;没有具体的对应事件。
    • contextLoadedApplicationContext创建并加载之后并在refresh之前调用;对应事件的类型是ApplicationPreparedEvent
    • finished:run方法结束之前调用;对应事件的类型是ApplicationReadyEventApplicationFailedEvent
  • 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
  • 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)
  • EnvironmentPostProcessorEnvironment 后置处理器,由 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:借助 ConfigurationClassParserConfigurationClassParser 递归地解析配置类并注册到 BeanDefinitionRegistry

  • ConditionEvaluator:根据 @Conditional 注解进行评估一个 Bean 定义是否应该注册。

5. SpringBoot 启动流程概要

  1. 创建一个 ConfigurableEnvironment,广播 ApplicationEnvironmentPreparedEvent 事件,ConfigFileApplicationListener 收到通知后利用 SPI 机制加载所有 EnvironmentPostProcessor 的实现类,触发其 postProcessEnvironment 方法。ConfigFileApplicationListener 自身也实现了 EnvironmentPostProcessor 接口,在它的 postProcessEnvironment 里通过内部类 Loader 加载所有的配置文件,并处理 profile,最终所有键值对都被添加到 Environment 里。
  2. 实例化一个 AnnotationConfigApplicationContext,实例化的过程中会把 应用指定的启动配置类、 ConfigurationClassPostProcessor 实例注册到底层的 BeanFacotry 实例里。
  3. 上下文 refresh 过程会触发执行 ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry 注册所有的 Bean 定义。
  4. 找出上下文里所有非延迟加载的单例的 BeanName,逐个实例化,实例化过程中应用 BeanPostProcessor 进行加工增强,得到最终的 Bean object 给应用使用。

欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。

SpringBoot 启动分析(一)》有一个想法

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据