ApplicationEvent 和 Listener 是 Spring 为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者模式,设计初衷在于对系统业务逻辑进行解耦,提高系统的可扩展性以及可维护性
一、Spring 常见内置事件
-
ApplicationContextEvent
- ApplicationContext 事件发布基类
-
ContextStartedEvent
- ApplicationContext 启动时发布该事件
-
ContextStoppedEvent
- ApplicationContext 停止时发布该事件
-
ContextRefreshedEvent
- ApplicationContext 刷新时发布该事件
-
ContextClosedEvent
- ApplicationContext 关闭时发布该事件
二、SpringBoot 常见内置事件
-
SpringApplicationEvent
- SpringApplication 事件发布基类
-
ApplicationStartingEvent
-
SpringApplication 启动时发布该事件
-
此时应用监听器 (ApplicationListener) 已注册,但应用环境 (Environment) 和应用上下文 (ApplicationContext) 尚未加载
-
-
ApplicationEnvironmentPreparedEvent
-
SpringApplication 启动时发布该事件
-
此时,应用环境 (Environment) 已加载,但应用上下文 (ApplicationContext) 尚未加载
-
-
ApplicationContextInitializedEvent
-
SpringApplication 启动时发布该事件
-
此时,应用上下文 (ApplicationContext) 已准备好,且应用上下文初始化器 (ApplicationContextInitializers) 已被调用,但 Bean 对象尚未加载
-
-
ApplicationPreparedEvent
-
SpringApplication 启动时发布该事件
-
此时,应用上下文 (ApplicationContext) 已准备充分但并未刷新
-
此阶段 Bean 对象将被加载,且可以使用应用环境 (Environment)
-
-
ApplicationStartedEvent
-
刷新应用上下文后发布该事件
-
此时,尚未调用任何 CommandLineRunner 和 ApplicationRunner 运行器
-
-
ApplicationReadyEvent
- 应用程序已准备就绪,并可以处理请求时发布该事件
-
ApplicationFailedEvent
- SpringApplication 启动失败时发布该事件
三、举例说明
-
MyApplicationEvent 事件,继承自 ApplicationEvent,其 msg 字段为需要发送的消息
public class MyApplicationEvent extends ApplicationEvent { private String msg; public MyApplicationEvent(Object source, String msg) { super(source); this.msg = msg; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
-
MsgController 消息控制层
@RestController @RequestMapping("/msg") public class MsgController { @Resource private MsgService msgService; @GetMapping("/send/{msg}") public String sendMsg(@PathVariable("msg") String msg) { msgService.sendMsg(msg); return "Msg sent successfully"; } }
-
MsgService 消息业务接口
public interface MsgService { void sendMsg(String msg); }
-
MsgService 消息业务接口实现类,注入 ApplicationContext,负责 MyApplicationEvent 事件的发布
@Service public class MsgServiceImpl implements MsgService { @Resource private ApplicationContext applicationContext; @Override public void sendMsg(String msg) { applicationContext.publishEvent(new MyApplicationEvent(this, msg)); } }
-
ApplicationListener 监听器,负责监听事件并进行业务流程,共有以下三种实现方式
-
使用 @EventListener 注解进行监听
@Component public class MyAnnotationApplicationListener { @EventListener public void receiveMsg(MyApplicationEvent myApplicationEvent) { System.out.println("MyAnnotationApplicationListener 接收消息: " + myApplicationEvent.getMsg()); } }
-
实现 ApplicationListener 接口进行监听
@Component public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> { @Override public void onApplicationEvent(MyApplicationEvent event) { System.out.println("MyApplicationListener 接收消息: " + event.getMsg()); } }
-
实现 SmartApplicationListener 接口进行监听
@Component public class MySmartApplicationListener implements SmartApplicationListener { @Override public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { // 只有 MyApplicationEvent 类型的事件才会被监听 return eventType == MyApplicationEvent.class; } @Override public boolean supportsSourceType(Class<?> sourceType) { // 只有在 MsgServiceImpl 内发布的 MyApplicationEvent 事件才会被监听 return sourceType == MsgServiceImpl.class; } @Override public void onApplicationEvent(ApplicationEvent event) { MyApplicationEvent myApplicationEvent = (MyApplicationEvent) event; System.out.println("MySmartApplicationListener 接收消息: " + myApplicationEvent.getMsg()); } }
-
SmartApplicationListener 接口继承自 ApplicationListener 接口
-
SmartApplicationListener 接口并提供了
supportsEventType()
方法和supportsSourceType()
两个方法用于监听控制,只有这两个方法都返回true
,才会执行onApplicationEvent()
方法中的监听业务流程
-
-
进行测试
-
在浏览器中请求接口
http://localhost:8080/msg/send/HelloWorld
-
控制台输出如上所示,三种方式实现了对 MyApplicationEvent 事件的监听
-
-
-
实现 SmartApplicationListener 接口进行有序监听
-
监听器监听事件是无序的,不过我们可以通过实现 SmartApplicationListener 接口来进行有序监听
-
SmartApplicationListener 接口除了提供了
supportsEventType()
方法和supportsSourceType()
两个方法用于监听控制,还提供了getOrder()
方法用于控制事件监听顺序,值越小优先级越高,执行顺序越靠前 -
MyFirstSmartApplicationListener 监听器,监听顺序为 1
@Component public class MyFirstSmartApplicationListener implements SmartApplicationListener { @Override public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { // 只有 MyApplicationEvent 类型的事件才会被监听 return eventType == MyApplicationEvent.class; } @Override public boolean supportsSourceType(Class<?> sourceType) { // 只有在 MsgServiceImpl 内发布的 MyApplicationEvent 事件才会被监听 return sourceType == MsgServiceImpl.class; } @Override public int getOrder() { return 1; } @Override public void onApplicationEvent(ApplicationEvent event) { MyApplicationEvent myApplicationEvent = (MyApplicationEvent) event; System.out.println("MyFirstSmartApplicationListener 接收消息: " + myApplicationEvent.getMsg()); } }
-
MySecondSmartApplicationListener 监听器,监听顺序为 2
@Component public class MySecondSmartApplicationListener implements SmartApplicationListener { @Override public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { // 只有 MyApplicationEvent 类型的事件才会被监听 return eventType == MyApplicationEvent.class; } @Override public boolean supportsSourceType(Class<?> sourceType) { // 只有在 MsgServiceImpl 内发布的 MyApplicationEvent 事件才会被监听 return sourceType == MsgServiceImpl.class; } @Override public int getOrder() { return 2; } @Override public void onApplicationEvent(ApplicationEvent event) { MyApplicationEvent myApplicationEvent = (MyApplicationEvent) event; System.out.println("MySecondSmartApplicationListener 接收消息: " + myApplicationEvent.getMsg()); } }
-
进行测试
-
在浏览器中请求接口
http://localhost:8080/msg/send/HelloWorld
-
控制台输出如上所示,通过 SmartApplicationListener 接口的
getOrder()
方法实现了对 MyApplicationEvent 事件的有序监听
-
-