事件监听注册的几种方式
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传递过来的


















