文章插图
监听器模型
说明事件监听机制可以理解为是一种观察者模式,有数据发布者(事件源)和数据接受者(监听器);
在JAVA中,事件对象都是继承java.util.EventObject对象,事件监听器都是java.util.EventListener实例;
EventObject对象不提供默认构造器,需要外部传递source参数,即用于记录并跟踪事件的来源;
Spring事件Spring事件对象为ApplicationEvent,继承EventObject,源码如下:
public abstract class ApplicationEvent extends EventObject { /*** Create a new ApplicationEvent.* @param source the object on which the event initially occurred (never {@code null})*/ public ApplicationEvent(Object source) {super(source);this.timestamp = System.currentTimeMillis(); }}
Spring事件监听器为ApplicationListener,继承EventListener,源码如下:public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {void onApplicationEvent(E var1);}
实现Spring事件监听有两种方式:- 面向接口编程,实现ApplicationListener接口;
- 基于注解驱动,@EventListener(Spring自定义的注解);
- 面向接口编程,实现ApplicationListener接口:
public class MyApplicationEvent extends ApplicationEvent {public MyApplicationEvent(Object source) {super(source);}}
自定义事件监听器:public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> {@Overridepublic void onApplicationEvent(MyApplicationEvent event) {System.out.println("收到事件:" + event);}}
启动服务并发布事件:public class ApplicationEventBootstrap {public static void main(String[] args) {AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext();// 注册自定义事件监听器context.addApplicationListener(new MyApplicationListener());// 启动上下文context.refresh();// 发布事件,事件源为Contextcontext.publishEvent(new MyApplicationEvent(context));// 结束context.close();}}
运行结果:收到事件:com.xx.MyApplicationEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@cb0ed20, started on Sat May 16 16:32:04 CST 2020]
- 使用注解 @EventListener实现Spring事件监听:
@Componentpublic class MyApplicationListener2 {@EventListener(MyApplicationEvent.class)public void onEvent(MyApplicationEvent event) {System.out.println("收到事件:" + event);}}
启动并发布事件:public class ApplicationEventBootstrap {public static void main(String[] args) {AnnotationConfigApplicationContext context =new AnnotationConfigApplicationContext();// 注册自定义事件监听器context.register(MyApplicationListener2.class);// 启动上下文context.refresh();// 发布事件,事件源为Contextcontext.publishEvent(new MyApplicationEvent(context));// 结束context.close();}}
运行结果:收到事件:com.xx.MyApplicationEvent[source=org.springframework.context.annotation.AnnotationConfigApplicationContext@cb0ed20, started on Sat May 16 16:32:04 CST 2020]
通过实例可以看出,上面两种方式都可正常发布和接收事件 。实现原理通过上面实例可以看出,context 可以发布事件,那底层是怎么发布的,让我们继续看源码:
public abstract class AbstractApplicationContext extends DefaultResourceLoaderimplements ConfigurableApplicationContext {protected void publishEvent(Object event, @Nullable ResolvableType eventType) {...getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);...}}
通过源码我们可以看出,事件应该是通过ApplicationEventMulticaster发布的,我们继续看:
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster
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> 。
推荐阅读
- 瞬间几千次的重复提交,我用Spring Boot+Redis扛住了
- 程序员必看:Spring Boot+Vue.js+FastDFS实现分布式图片服务器!
- 深入浅出为什么你的网页需要CSP?【前端篇】
- Springboot整合https原来这么简单
- 深入浅出React.js 性能分析
- Spring Boot 一个接口同时支持 form 表单、form-data、json 优雅写法
- Spring Session 原理分析
- 程序员云旅游:10分钟带你走完SpringMVC里一次HTTP请求处理之路
- 深入浅出微服务架构:一分钟让你轻松上手Docker容器
- Java程序员只会CRUD连Spring事务传播机制都不懂?