SpringApplicationRunListener 的使用
基本使用
(1)实现 SpringApplicationRunListener
package com.example.demo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
@Slf4j
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
@Override
public void running(ConfigurableApplicationContext context) {
log.info("running");
}
}
(2)META-INF/spring.factories
配置:
org.springframework.boot.SpringApplicationRunListener=\
com.example.demo.MySpringApplicationRunListener
启动出现如下异常:
Exception in thread "main" java.lang.IllegalArgumentException: Cannot instantiate interface org.springframework.boot.SpringApplicationRunListener : com.example.demo.MySpringApplicationRunListener
at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:475)
at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:457)
at org.springframework.boot.SpringApplication.getRunListeners(SpringApplication.java:445)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:328)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332)
at com.example.demo.DemoApplication.main(DemoApplication.java:12)
Caused by: java.lang.NoSuchMethodException: com.example.demo.MySpringApplicationRunListener.<init>(org.springframework.boot.SpringApplication, [Ljava.lang.String;)
at java.lang.Class.getConstructor0(Class.java:3082)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:470)
... 6 more
(3)MySpringApplicationRunListener
新增构造函数
@Slf4j
public class MySpringApplicationRunListener implements SpringApplicationRunListener {
// Spring 容器实例化使用
public MySpringApplicationRunListener(SpringApplication application, String[] args) {
}
@Override
public void running(ConfigurableApplicationContext context) {
log.info("running");
}
}
启动后,控制台输出如下:
2021-07-26 19:39:22.666 INFO 1272 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication using Java 1.8.0_292 on mk with PID 1272 (F:\tmp\demo\target\classes started by meikai in F:\tmp\demo)
2021-07-26 19:39:22.668 INFO 1272 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to default profiles: default
2021-07-26 19:39:23.208 INFO 1272 --- [ main] o.s.cloud.context.scope.GenericScope : BeanFactory id=6c8dcb71-9100-3fb1-9449-64ede168f178
2021-07-26 19:39:23.383 INFO 1272 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2021-07-26 19:39:23.389 INFO 1272 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2021-07-26 19:39:23.390 INFO 1272 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.50]
2021-07-26 19:39:23.452 INFO 1272 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2021-07-26 19:39:23.452 INFO 1272 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 750 ms
2021-07-26 19:39:25.015 INFO 1272 --- [ main] o.s.cloud.commons.util.InetUtils : Cannot determine local hostname
2021-07-26 19:39:25.084 INFO 1272 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2021-07-26 19:39:26.390 INFO 1272 --- [ main] o.s.cloud.commons.util.InetUtils : Cannot determine local hostname
2021-07-26 19:39:26.397 INFO 1272 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 5.436 seconds (JVM running for 6.259)
2021-07-26 19:39:26.399 INFO 1272 --- [ main] c.e.demo.MySpringApplicationRunListener : running
测试优先级
(1)在上文的基础上,再实现一个 SpringApplicationRunListener
package com.example.demo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.annotation.Order;
@Slf4j
@Order(1)
public class MySpringApplicationRunListener2 implements SpringApplicationRunListener {
// Spring 容器实例化使用
public MySpringApplicationRunListener2(SpringApplication application, String[] args) {
}
@Override
public void running(ConfigurableApplicationContext context) {
log.info("running");
}
}
(2)META-INF/spring.factories
配置如下:
org.springframework.boot.SpringApplicationRunListener=\
com.example.demo.MySpringApplicationRunListener,\
com.example.demo.MySpringApplicationRunListener2
启动后,控制台输出如下:
2021-07-26 19:48:38.858 INFO 17836 --- [ main] c.e.d.MySpringApplicationRunListener2 : running
2021-07-26 19:48:38.859 INFO 17836 --- [ main] c.e.demo.MySpringApplicationRunListener : running
MySpringApplicationRunListener
没有配置 Order,默认值为 Integer.MAX_VALUE
,比 MySpringApplicationRunListener2
配置的 Order 值 1
大,所以 MySpringApplicationRunListener2
的优先级更高。
监听 ApplicationReadyEvent 事件
源码解读
(1)在 spring-boot-2.5.3.jar
的 META-INF/spring.factories
文件中有如下配置:
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
(2)EventPublishingRunListener
package org.springframework.boot.context.event;
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
@Override
public int getOrder() {
// 优先级为 0,order 越小,优先级越高
return 0;
}
@Override
public void running(ConfigurableApplicationContext context) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}
}
(3)AnnotationAwareOrderComparator
package org.springframework.core.annotation;
public class AnnotationAwareOrderComparator extends OrderComparator {
/**
* Shared default instance of {@code AnnotationAwareOrderComparator}.
*/
public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
public static void sort(List<?> list) {
if (list.size() > 1) {
list.sort(INSTANCE);
}
}
}
package org.springframework.core;
public class OrderComparator implements Comparator<Object> {
@Override
public int compare(@Nullable Object o1, @Nullable Object o2) {
return doCompare(o1, o2, null);
}
private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
boolean p1 = (o1 instanceof PriorityOrdered);
boolean p2 = (o2 instanceof PriorityOrdered);
if (p1 && !p2) {
return -1;
}
else if (p2 && !p1) {
return 1;
}
int i1 = getOrder(o1, sourceProvider);
int i2 = getOrder(o2, sourceProvider);
return Integer.compare(i1, i2);
}
protected int getOrder(@Nullable Object obj) {
if (obj != null) {
Integer order = findOrder(obj);
if (order != null) {
return order;
}
}
// 如果没有配置,默认返回 Integer.MAX_VALUE
return Ordered.LOWEST_PRECEDENCE;
}
}
测试
(1)监听 ApplicationReadyEvent 事件
@Component
@Slf4j
public class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
log.info("ApplicationListener event:{}", event);
}
@EventListener(classes = {ApplicationReadyEvent.class})
public void listen(ApplicationReadyEvent event) {
log.info("@EventListener event:{}", event);
}
}
(2)在上文的基础上,再实现一个 SpringApplicationRunListener
@Slf4j
@Order(-1)
public class MySpringApplicationRunListener3 implements SpringApplicationRunListener {
// Spring 容器实例化使用
public MySpringApplicationRunListener3(SpringApplication application, String[] args) {
}
@Override
public void running(ConfigurableApplicationContext context) {
log.info("running");
}
}
(3)META-INF/spring.factories 配置如下:
org.springframework.boot.SpringApplicationRunListener=\
com.example.demo.MySpringApplicationRunListener,\
com.example.demo.MySpringApplicationRunListener2,\
com.example.demo.MySpringApplicationRunListener3
控制台输出:
2021-07-26 21:57:35.481 INFO 14332 --- [ main] c.e.d.MySpringApplicationRunListener3 : running
2021-07-26 21:57:35.481 INFO 14332 --- [ main] com.example.demo.MyApplicationListener : ApplicationListener event:org.springframework.boot.context.event.ApplicationReadyEvent[source=org.springframework.boot.SpringApplication@2c708440]
2021-07-26 21:57:35.481 INFO 14332 --- [ main] com.example.demo.MyApplicationListener : @EventListener event:org.springframework.boot.context.event.ApplicationReadyEvent[source=org.springframework.boot.SpringApplication@2c708440]
2021-07-26 21:57:35.481 INFO 14332 --- [ main] c.e.d.MySpringApplicationRunListener2 : running
2021-07-26 21:57:35.481 INFO 14332 --- [ main] c.e.demo.MySpringApplicationRunListener : running
-
MySpringApplicationRunListener
没有配置 Order,默认值为Integer.MAX_VALUE
。 -
MySpringApplicationRunListener2
配置的 Order 值为1
。 -
MySpringApplicationRunListener3
配置的 Order 值为-1
。 -
EventPublishingRunListener
配置的 Order 值为0
。
所以,执行顺序为:
- (1)
MySpringApplicationRunListener3
- (2)
EventPublishingRunListener
,及其监听的 ApplicationReadyEvent 处理。 - (3)
MySpringApplicationRunListener2
- (4)
MySpringApplicationRunListener
执行顺序和控制台输出的顺序符合。
参考
作者:蓝笔头
原文链接:https://www.jianshu.com/p/c0e29d6c0274