[SpringBoot] 源码解读:ApplicationStartedEvent 和 ApplicationReadyEvent

3,203 阅读2分钟

一张图看懂 ApplicationStartedEvent 和 ApplicationReadyEvent 的区别。


在编写 SpringBoot 程序时,有时候需要在程序启动的时候做一些业务逻辑,比如读取一些自定义的配置文件,初始化一些长链接等等。

这时候,可以编写一个 Java 类,监听程序启动状态的一些事件来触发这些业务逻辑。

适用于这种业务逻辑的事件有两种: ApplicationStartedEventApplicationReadyEvent

这两种事件都是在程序启动之后触发,触发时应用上下文都已经准备好,所有的(除了延迟初始化的)的 bean 对象都是可用的,原理上都可以用来触发我们的业务逻辑。

但是实际应用中,还是要注意到他们之间的差别,从而选择合适的事件类型。

从上面的 SpringApplication.java 源码中可以看到, ApplicationStartedEvent 是在第 1 个标示的地方, 也即 332 行触发的,而 ApplicationReadyEvent 是在第 2 个标示的地方,也即 341 行触发的。

这两个事件之间,在 333 行,callRunner 方法中,SpringBoot 同步调用了程序里所有 ApplicationRunnerCommandLineRunner 的实现类的 run 方法

这意味着

  • ApplicationStartedEvent 事件触发时,所有的 runner 都还没有运行
  • 只有所有的 runner 全部运行完成(没有异常),才会触发 ApplicationReadyEvent

所以,如果你的业务逻辑和 runner 的运行没有先后顺序要求,而且不依赖 runner 的执行结果,那么这两个事件都可以使用,否则就应该使用 ApplicationReadyEvent


下面举一个极端的例子。(没有启用异步事件处理的情况下

我们有一个 DataStore.java, 存储了一个公共的 int 值, 在初始化的时候设置为 1

再注册一个 CommandLineRunner 类, 在这个 runner 类中将这个公共 int 值自增一次

再添加一个 ApplicationStartedEvent 事件的监听者,触发时打印出这个公共 int 值

再添加一个 ApplicationReadyEvent 事件的监听者,触发时打印出这个公共 int 值

运行这个 SpringBoot 程序,那么:

  • ApplicationStartedEvent 事件的监听者打印出来的 int 值是 1
  • 这个 CommandLineRunner 类看到的 int 值是 1,将其自增 1
  • ApplicationReadyEvent 事件的监听者打印出来的 int 值是 2