事件监听注册的几种方式
ApplicationContext下面简称AC
1.构建SpringApplication时注册(可以监听AC启动阶段事件)
// 方式一:
//写法1
SpringApplication application = new SpringApplicationBuilder().listeners(new ApplicationPidFileWriter()).build(args);
//写法2
SpringApplication springApplication = new SpringApplication();
application.addListeners(new ApplicationPidFileWriter());
2.在META-INF/spring.factories中注册(可以监听AC启动阶段事件)
org.springframework.context.ApplicationListener=org.springframework.boot.context.ApplicationPidFileWriter
3.bean扫描(部分AC启动阶段事件无法监听)
@Component
public class ApplicationAvailabilityExporter {
@EventListener
public void onStateChange(AvailabilityChangeEvent event) {
AvailabilityState state = event.getState();
if (state.equals(ReadinessState.ACCEPTING_TRAFFIC)) {
System.out.println("应用程序已经可以接受外部请求");
} else if (state.equals(ReadinessState.REFUSING_TRAFFIC)) {
System.out.println("应用程序拒绝接受外部请求");
} else if (state.equals(LivenessState.BROKEN)) {
System.out.println("应用程序不可用");
} else if (state.equals(LivenessState.CORRECT)) {
System.out.println("应用程序正常");
}
}
}
监听时机问题
springboot里面有部分事件是在ApplicationContext创建之前发布的。所以这就有有了上面的前两种注册方式,第三种注册方式,是我们最常见,也是业务中最常用的一种方式。
比如:
ApplicationStartingEvent
在SpringApplication的run方法内,它发布的时间会很早,在SpringApplicationRunListeners里面就包含着通过方法一和方法二注册的监听器,但是这个时候不包含第三种。
监听器注册演示
@SpringBootApplication
public class Study03Application {
public static void main(String[] args) {
try {
SpringApplication application = new SpringApplicationBuilder(Study03Application.class)
.bannerMode(Banner.Mode.OFF)
// 指定web应用程序类型,SERVLET,REACTIVE,NONE
// NONE 就是表示不对外提供web服务
.web(WebApplicationType.SERVLET)
.allowCircularReferences(true) // 是否允许循环引用
.build();
// ApplicationListener 分为两种,一种是在spring容器初始化完成之前就需要监听事件的,一种是在spring容器初始化完成之后监听事件的
// 第一种比如: 应用程序的pid写入文件,当程序启动后spring会发送ApplicationPreparedEvent事件,但是这个时候,spring还没有扫描所有组件进行初始化。
// 这个时候就无法监听
//application.addListeners(new ApplicationPidFileWriter());
application.addListeners(new WebServerPortFileWriter());
// 第二种是比较常见的,这里就不演示了
application.run(args);
} catch (Exception ex){
ex.printStackTrace();
}
}
在resources目录下的META-INF/spring.factories中添加下面内容
org.springframework.context.ApplicationListener=org.springframework.boot.context.ApplicationPidFileWriter
启动后会自动生成这两个内容
ApplicationContext初始化过程中发布的事件
-
ApplicationStartingEvent是在
DefaultBootstrapContext
和SpringApplicationRunListeners
刚初始化完
-
ApplicationEnvironmentPreparedEvent是在环境信息初始化完成
-
ApplicationContextInitializedEvent是在ApplicationContext初始化完成之后
- ApplicationPreparedEvent 在refresh之前,在bean声明被加载之后。
- ApplicationStartedEvent 在ac的refresh之后,在ApplicationRunner和CommandRunner之前发布
- AvailabilityChangeEvent 在started之后发布
- ApplicationReadyEvent 是在ApplicationRunner和CommandRunner之后执行
- AvailabilityChangeEvent 是在ready之后执行
- ApplicationFailedEvent 是在应用应用程序启动失败时发布
- WebServerInitializedEvent 在WebServer准备好后发布
- ContextRefreshedEvent 是在AC的refresh执行完成后
基于spring事件驱动机制下,存在多个ApplicationContext的情况下,子AC发送的消息会被传递到父AC中。
在多层级下的ApplicationContext,一个监听器可能收到多个同样的事件,这就是因为事件向父类传递导致的,由此衍伸出,可以通过实现ApplicationContextAwre或者@Autowire 来注入AC进行区分是子类的AC传递过来的还是父AC传递过来的