Spring/SpringBoot 事件监听机制是什么
发布时间:2021-11-09 09:02 所属栏目:53 来源:互联网
导读:本篇文章给大家分享的是有关Spring/SpringBoot 事件监听机制是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。 事件监听机制可以理解为是一种观察者模式,有数据发布者(事件源)和数据
本篇文章给大家分享的是有关Spring/SpringBoot 事件监听机制是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。 事件监听机制可以理解为是一种观察者模式,有数据发布者(事件源)和数据接受者(监听器); 在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事件监听有两种方式: 鸿蒙官方战略合作共建——HarmonyOS技术社区 面向接口编程,实现ApplicationListener接口; 基于注解驱动,@EventListener(Spring自定义的注解); 实例: 面向接口编程,实现ApplicationListener接口: 自定义事件对象: public class MyApplicationEvent extends ApplicationEvent { public MyApplicationEvent(Object source) { super(source); } } 自定义事件监听器: public class MyApplicationListener implements ApplicationListener<MyApplicationEvent> { @Override public 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(); // 发布事件,事件源为Context context.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事件监听: @Component public 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(); // 发布事件,事件源为Context context.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 DefaultResourceLoader implements 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。 private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { listener.onApplicationEvent(event); 最后就使用对应的ApplicationListener进行接收和处理就行了,那么ApplicationListener是什么时候注册的呢? 如何添加ApplicationListener? 直接添加,使用content.addApplicationListener(上面实例中有使用); 将自定义的ApplicationListener注册为一个Bean,Spring再初始化Bean之后会添加,具体代码在ApplicationListenerDetector#postProcessAfterInitialization,判断一个Bean如果是ApplicationListener,则也是使用context.addApplicationListener添加; 使用注解@EventListener,在初始化Bean之后,会在EventListenerMethodProcessor中进行处理和添加; 第三种实现的源码如下( EventListenerMethodProcessor中): private void processBean(final String beanName, final Class<?> targetType) { .... // 获取public 且有@EventListener的方法 AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class)); ... ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse); // 添加监听器 context.addApplicationListener(applicationListener); } Spring内建事件 ContextRefreshedEvent: Spring应用上下文就绪事件; ContextStartedEvent: Spring应用上下文启动事件; ContextStopedEvent: Spring应用上下文停止事件; ContextClosedEvent: Spring应用上下文关闭事件; Spring Boot事件 Spring Boot事件是在Spring事件基础上进行的封装 public abstract class SpringApplicationEvent extends ApplicationEvent 事件对象改为SpringApplicationEvent,事件源为SpringApplication(Spring事件源为Context); 底层发布事件还是使用 SimpleApplicationEventMulticaster 对象,不过有点需要说明的是,Spring Boot 1.4开始,SpringApplication和ApplicationContext使用的都是 SimpleApplicationEventMulticaster实例,但是两者属于不同的对象(1.0 ~ 1.3版本是同一个对象); 事件回顾: public class EventBootstrap { public static void main(String[] args) { new SpringApplicationBuilder(Object.class) .listeners(event -> { System.out.println("事件对象:" + event.getClass().getSimpleName() + " ,事件源:" + event.getSource().getClass().getSimpleName()); }) .web(WebApplicationType.NONE) .run(args) .close(); } } 运行结果: 事件对象:ApplicationContextInitializedEvent ,事件源:SpringApplication 事件对象:ApplicationPreparedEvent ,事件源:SpringApplication 事件对象:ContextRefreshedEvent ,事件源:AnnotationConfigApplicationContext 事件对象:ApplicationStartedEvent ,事件源:SpringApplication 事件对象:ApplicationReadyEvent ,事件源:SpringApplication 事件对象:ContextClosedEvent ,事件源:AnnotationConfigApplicationContext 从结果可以看出,事件对象类型和事件源,以及事件发布顺序。 (编辑:ASP站长网) |
相关内容
网友评论
推荐文章
热点阅读