main方法启动时,springBoot启动流程的各个生命周期会以事件通知的方式,把事件告知其他程序
前期通过spring-spi获取所有监听事件的类

  • spring启动的大体流程为以下的几个方法
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    public class EventPublishingRunListener implements SpringApplicationRunListener {
    ...
    private final SimpleApplicationEventMulticaster initialMulticaster = new SimpleApplicationEventMulticaster();

    public EventPublishingRunListener(SpringApplication application, String[] args) {
    // 通过springSPI获取所有的ApplicationListener,并copy到initialMulticaster
    // 如果ApplicationListener是以注解形式使用,非spi配置的。会在[refresh阶段](/posts/springbeanfactory流程解析)扫描所有以注解形式配置的listener
    // 也就是说注解形式配置的listener,监听refresh之前的事件都是伪事件
    for (ApplicationListener<?> listener : application.getListeners()) {
    this.initialMulticaster.addApplicationListener(listener);
    }
    }

    // 1 开始
    @Override
    public void starting() {
    this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }

    // 2 环境准备
    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
    this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
    }
    /**
    protected void applyInitializers(ConfigurableApplicationContext context) {
    for (ApplicationContextInitializer initializer : getInitializers()) {
    Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
    ApplicationContextInitializer.class);
    Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
    initializer.initialize(context);
    }
    }
    */

    // prepared之前 会调用 mian方法启动的SpringApplication 内置的 initialize,如上面的注释的代码
    // 3 上下文准备
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
    this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
    }

    // 4 上下文已加载
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
    for (ApplicationListener<?> listener : this.application.getListeners()) {
    if (listener instanceof ApplicationContextAware) {
    ((ApplicationContextAware) listener).setApplicationContext(context);
    }
    context.addApplicationListener(listener);
    }
    this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
    }
    // contextLoaded之后 会调用 [context.refresh](/posts/springbeanfactory流程解析),会实例化所有的bean(单例的、notLazy的),包括以注解形式配置的listener

    // 5 启动完成
    @Override
    public void started(ConfigurableApplicationContext context) {
    // 在refresh阶段后,后续的事件会通过context发出,context持有beanFactory,beanFactory在refresh期间会扫描所有的listener。所以就不能仅仅调用spi配置的listener了
    context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
    AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
    }

    // 6 运行中
    @Override
    public void running(ConfigurableApplicationContext context) {
    // 通过context发出事件,context持有beanFactory,beanFactory会扫描所有的ApplicationListener。
    context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
    AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
    }

    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
    ...
    }
    ...
    }

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。

启动流程

1. starting -》ApplicationStartingEvent

正在进行时、代表容器刚开始运行了---发出程序开始事件
springDevTools就是用到了此事件,把类加载器给换了一下,起到了热部署的作用,后期咱们会有详细的分析

2. environmentPrepared -》ApplicationEnvironmentPreparedEvent

配置环境变量加载配置文件资源等---发出环境配置已就绪事件
nacos和springCloud远程加载配置文件就是用到了此事件,后期咱们会有详细的分析

事件发出之后,马上就要实例化ApplicationContext了,不同的WebApplicationType,context不同
不管什么样的context,都会持有beanFactory,并且都会向beanFactory注册一个非常重要的bean
注册代码AnnotationConfigUtils#registerAnnotationConfigProcessors
=ConfigurationClassPostProcessor,在beanFactory执行后置处理时,会调用此类,并扫描所有的bean

实例化完后会发布事情通知容器已经实例化,调用ApplicationContextInitializer的initialize

3. contextPrepared -》ApplicationContextInitializedEvent

容器准备---发出应用程序上下文初始化事件
contextPrepared之后springBoot会把main方法所在的类注册到beanFactory中
beanFactory在执行beanFactory执行后置处理时,会调用ConfigurationClassPostProcessor
ConfigurationClassPostProcessor通过扫描beanFactory所有注册的bean上的注解继而扫描其他的bean(包)

4. contextLoaded -》ApplicationPreparedEvent

容器已加载完毕---发出应用程序已准备就绪事件

contextLoaded之后 会调用 context.refresh,会实例化所有的bean(单例的、notLazy的)
refresh阶段比较复杂,基本上都是操作beanFactory完成bean的扫描、组装、初始化等逻辑
beanFactory可参考springBeanFactory流程解析

5. started -》ApplicationStartedEvent

发出应用程序已启动事件

6. running -》ApplicationReadyEvent

运行中---发出程序已做完事件

--failed -》ApplicationFailedEvent
启动失败时的事件处理器,spring默认就是打印日志。
我们可以实现此事件的监听,项目启动失败之后直接报警等

总结

ApplicationContext这个是spring的容器(非常重要),启动的流程基本上都是围绕着他展开。
从各个事件的通知事件我们不难看出。从最开始的starting、environmentPrepared都是为applicationContext做准备。根据不同的WebType实例化不同的applicationContext,之后context会持有environment
environment包含了所有的配置文件
然后再以context为中心进行initialize事件的触发、然后contextPrepared、contextLoaded、context.refresh
refresh工作比较复杂也是beanFactory的核心,具体可参考springBeanFactory流程解析 最后在做结尾的工作started和running