一张图看懂 ApplicationStartedEvent 和 ApplicationReadyEvent 的区别。
在编写 SpringBoot 程序时,有时候需要在程序启动的时候做一些业务逻辑,比如读取一些自定义的配置文件,初始化一些长链接等等。
这时候,可以编写一个 Java 类,监听程序启动状态的一些事件来触发这些业务逻辑。
适用于这种业务逻辑的事件有两种: ApplicationStartedEvent 和 ApplicationReadyEvent
这两种事件都是在程序启动之后触发,触发时应用上下文都已经准备好,所有的(除了延迟初始化的)的 bean 对象都是可用的,原理上都可以用来触发我们的业务逻辑。
但是实际应用中,还是要注意到他们之间的差别,从而选择合适的事件类型。
从上面的 SpringApplication.java 源码中可以看到, ApplicationStartedEvent 是在第 1 个标示的地方, 也即 332 行触发的,而 ApplicationReadyEvent 是在第 2 个标示的地方,也即 341 行触发的。
这两个事件之间,在 333 行,callRunner 方法中,SpringBoot 同步调用了程序里所有 ApplicationRunner 和 CommandLineRunner 的实现类的 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