public class EmailEvent extends ApplicationEvent { private String address; private String text; public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getText() { return text; } public void setText(String text) { this.text = text; } public EmailEvent(Object source, String address, String text) { super(source); this.address = address; this.text = text; } public EmailEvent(Object source) { super(source); } //......address和text的setter、getter } //容器刷新监听 @Component public class TestApplicationListener implements ApplicationListener<ContextRefreshedEvent> { Logger log = LoggerFactory.getLogger(TestApplicationListener.class); @Override public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) { log.info(contextRefreshedEvent.toString()); log.info("TestApplicationListener.................................."); } } @Component //public class EmailNotifier implements ApplicationListener { public class EmailNotifier implements ApplicationListener<EmailEvent> { Logger log = LoggerFactory.getLogger(EmailNotifier.class); @Override public void onApplicationEvent(ApplicationEvent event) { //if (event instanceof EmailEvent) { EmailEvent emailEvent = (EmailEvent) event; log.info("邮件地址:" + emailEvent.getAddress()); log.info("邮件内容:" + emailEvent.getText()); //} else { // log.info("容器本身事件:" + event); //} } //注解方式 @Component public class EmailNotifier { Logger log = LoggerFactory.getLogger(EmailNotifier.class); @EventListener(EmailEvent.class) public void onApplicationEvent(ApplicationEvent event) { EmailEvent emailEvent = (EmailEvent) event; log.info("邮件地址:" + emailEvent.getAddress()); log.info("邮件内容:" + emailEvent.getText()); }
@SpringBootTest(classes = Springapplication22.class) //springboot启动类,依靠启动类找扫描springcontext的bean @RunWith(SpringRunner.class) public class ListenerTest { @Autowired ApplicationContext context; @Test public void test1() { //创建一个ApplicationEvent对象 EmailEvent event = new EmailEvent("hello", "abc@163.com", "This is a test"); //主动触发该事件 context.publishEvent(event); } }
贴个主要的源码
Spring 中事件发布都是通过SimpleApplicationEventMulticaster来实现的
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
// 异步
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
可以看出,如果设置了Executor则异步发送,否则同步;而且可以看出通过 resolveDefaultEventType(event) 对发布的事件类型进行了校验,这就是为什么我们可以直接使用泛型来指定我们想接收的事件对象, 比如上面的ApplicationListener<MyApplicationEvent>。
也就是说发布事件event后,会找到对应事件的event的listener,发出通知。
如果没有加泛型,事件发生都会得到通知。
Spring内建事件
- ContextRefreshedEvent: Spring应用上下文就绪事件;
- ContextStartedEvent: Spring应用上下文启动事件;
- ContextStopedEvent: Spring应用上下文停止事件;
- ContextClosedEvent: Spring应用上下文关闭事件;
参考:https://zhuanlan.zhihu.com/p/145927110