千家信息网

Spring/SpringBoot 事件监听机制是什么

发表于:2024-11-27 作者:千家信息网编辑
千家信息网最后更新 2024年11月27日,本篇文章给大家分享的是有关Spring/SpringBoot 事件监听机制是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。事件监听机
千家信息网最后更新 2024年11月27日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 extends EventListener {     void onApplicationEvent(E var1); }

实现Spring事件监听有两种方式:

  1. 鸿蒙官方战略合作共建--HarmonyOS技术社区

  2. 面向接口编程,实现ApplicationListener接口;

  3. 基于注解驱动,@EventListener(Spring自定义的注解);

实例:

面向接口编程,实现ApplicationListener接口:

自定义事件对象:

public class MyApplicationEvent extends ApplicationEvent {     public MyApplicationEvent(Object source) {         super(source);     } }

自定义事件监听器:

public class MyApplicationListener implements ApplicationListener {     @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?

  1. 直接添加,使用content.addApplicationListener(上面实例中有使用);

  2. 将自定义的ApplicationListener注册为一个Bean,Spring再初始化Bean之后会添加,具体代码在ApplicationListenerDetector#postProcessAfterInitialization,判断一个Bean如果是ApplicationListener,则也是使用context.addApplicationListener添加;

  3. 使用注解@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

从结果可以看出,事件对象类型和事件源,以及事件发布顺序。

以上就是Spring/SpringBoot 事件监听机制是什么,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注行业资讯频道。

事件 对象 监听 监听器 上下 上下文 实例 源码 接口 注解 结果 应用 机制 运行 就是 底层 方式 更多 知识 篇文章 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 网络安全防护喷雾测评 联通服务器坏了怎么上网 增强信息网络安全防范能力 王者营地我的服务器改掉 服务器集群与负载均衡 软件开发团队介绍大学生 oracle数据库的常见索引 我的世界pe开服务器 静安区品质软件开发销售公司 乡镇网络安全保障自查报告 软件开发怎么写专业特长 证明公司软件开发能力的佐证 部分阅读是什么意思读秀数据库 web选择题界面数据库 java 数据库多线程 如何获取别人服务器id 网络安全存在的问题和下一步打算 江津区提供软件开发服务代理商 网络安全渗透工程师难么 怎么修改数据库结构 YQCTF网络安全大赛 软件开发产品的图标 央企网络安全攻防大赛 东城区定制软件开发直销价 创建数据库的三大方法 部分阅读是什么意思读秀数据库 龙之谷双平台服务器 对于数据库的三个基本表…… 徐州嘿逗科技互联网推广 服务器bios测试主要测试什么
0