Spring Boot-5-自定义监听器

了解了监听器的工作原理之后,我们来看一下自定义的监听器如何实现

监听器的实现跟之前的系统初始化器的实现基本是一致的

第一种方式

创建监听器,实现 ApplicationListener ,泛型是些对应的感兴趣的事件,如下:

1
2
3
4
5
6
7
8
9
10
@Order(1)
@Slf4j
public class FirstListener implements ApplicationListener<ApplicationStartedEvent> {

@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
log.info("监听到:{}", event.getClass().getName());
}

}

和系统初始化器一样,也需要在 spring.factories 中配置,如下:

1
org.springframework.context.ApplicationListener=com.zhou.springboot.example.listener.FirstListener

第二种方式

1
2
3
4
5
6
7
8
9
@Order(2)
@Slf4j
public class SecondListener implements ApplicationListener<ApplicationStartedEvent> {

@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
log.info("监听到:{}", event.getClass().getName());
}
}

修改启动类,如下:

1
2
3
4
5
6
7
8
9
10
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(App.class);
springApplication.addInitializers(new SecondInitializer());

springApplication.addListeners(new SecondListener());
springApplication.run(args);
}
}

第三种方式

1
2
3
4
5
6
7
8
9
10
@Order(3)
@Slf4j
public class ThirdListener implements ApplicationListener<ApplicationStartedEvent> {

@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
log.info("监听到:{}", event.getClass().getName());
}

}

在 application 配置文件中配置

1
2
3
context:  
listener:
classes: com.zhou.springboot.example.listener.ThirdListener

第四种方式

前面三种方式都是和系统初始化器的配置方法一样的,监听器还有一种实现方式如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Order(4)
@Slf4j
public class FourthListener implements SmartApplicationListener {

@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationStartedEvent.class.isAssignableFrom(eventType) ||
ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}

@Override
public void onApplicationEvent(ApplicationEvent event) {
log.info("监听到:{}", event.getClass().getName());
}
}

这里是实现 SmartApplicationListener 接口, 在 supportsEventType() 方法中,配置自己感兴趣的事件,然后下面的 onApplicationEvent() 是具体的处理方法

同样的,这个监听器也是需要加到配置中去的,上面三种方式随便哪一种都行, 比如加到 application 配置文件中去:

1
2
3
context: 
listener:
classes: com.zhou.springboot.example.listener.ThirdListener,com.zhou.springboot.example.listener.FourthListener

运行测试

启动项目,日志如下:

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
  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.4.RELEASE)

2020-02-03 17:27:35.225 INFO 8832 --- [ main] c.z.s.e.initializers.ThirdInitializer : ThirdInitializer done...
2020-02-03 17:27:35.232 INFO 8832 --- [ main] c.z.s.e.initializers.FirstInitializer : FirstInitializer done...
2020-02-03 17:27:35.232 INFO 8832 --- [ main] c.z.s.e.initializers.SecondInitializer : SecondInitializer done...
2020-02-03 17:27:35.258 INFO 8832 --- [ main] com.zhou.springboot.example.App : Starting App on DESKTOP-B1V47DV with PID 8832 (D:\Demo\SpringBoot\spring-boot-example\build\classes\java\main started by Administrator in D:\Demo\SpringBoot\spring-boot-example)
2020-02-03 17:27:35.260 INFO 8832 --- [ main] com.zhou.springboot.example.App : No active profile set, falling back to default profiles: default
2020-02-03 17:27:35.368 INFO 8832 --- [ main] c.z.s.example.listener.FourthListener : 监听到:org.springframework.boot.context.event.ApplicationPreparedEvent
2020-02-03 17:27:37.582 INFO 8832 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-02-03 17:27:37.609 INFO 8832 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-02-03 17:27:37.610 INFO 8832 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.30]
2020-02-03 17:27:37.930 INFO 8832 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-02-03 17:27:37.930 INFO 8832 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2559 ms
2020-02-03 17:27:38.360 INFO 8832 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-02-03 17:27:38.771 INFO 8832 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-02-03 17:27:38.779 INFO 8832 --- [ main] com.zhou.springboot.example.App : Started App in 4.564 seconds (JVM running for 9.864)
2020-02-03 17:27:38.780 INFO 8832 --- [ main] c.z.s.example.listener.ThirdListener : 监听到:org.springframework.boot.context.event.ApplicationStartedEvent
2020-02-03 17:27:38.780 INFO 8832 --- [ main] c.z.s.example.listener.FourthListener : 监听到:org.springframework.boot.context.event.ApplicationStartedEvent
2020-02-03 17:27:38.781 INFO 8832 --- [ main] c.z.s.example.listener.FirstListener : 监听到:org.springframework.boot.context.event.ApplicationStartedEvent
2020-02-03 17:27:38.781 INFO 8832 --- [ main] c.z.s.example.listener.SecondListener : 监听到:org.springframework.boot.context.event.ApplicationStartedEvent

这里可以看到 FourthListener 执行了两次,因为我们上面配置了两种事件, 然后同样的 application 配置文件指定的要优先于其他方式,原理和系统初始化器一样

总结

自定义监听器的三种实现方式:

  • 定义在 spring.factories 中,被 SpringFactoriesLoader 发现注册.
  • 在 SpringApplication 初始化完毕之后手动添加
  • 定义成环境变量,被 DelegatingApplicationListener 发现注册