Spring Boot(六)自定义事件及监听

【SpringBoot3】Spring Boot Event 自定义事件的发布与监听 Spring Boot自定义事件是Spring框架中事件处理机制的一种扩展,它允许开发者在Spring Boot应用程序中定义、发布和监听自己的事件。这些事件可以用于在应用程序的不同组件之间进行通信,实现解耦和异步处理。通过自定义事件,开发者可以更加灵活地处理业务逻辑,提高系统的可扩展性和可维护性。 阅读详情

事件及监听并不是SpringBoot的新功能,Spring框架早已提供了完善的事件监听机制,在Spring框架中实现事件监听的流程如下:

  1. 自定义事件,继承org.springframework.context.ApplicationEvent抽象类

  2. 定义事件监听器,实现org.springframework.context.ApplicationListener接口

  3. 在Spring容器中发布事件

实现自定义事件及监听

  • 定义事件
//自定义事件
public class ApplicationEventTest extends ApplicationEvent {
    public ApplicationEventTest(Object source) {
        super(source);
    }
    /**
     * 事件处理事项
     * @param msg
     */
    public void printMsg(String msg)
    {
        System.out.println("监听到事件:"+ApplicationEventTest.class);
    }
}
  • 定义监听器
//自定义事件监听器
//@Component
public class ApplicationListenerTest implements ApplicationListener<ApplicationEventTest> {
    @Override
    public void onApplicationEvent(ApplicationEventTest event) {
        event.printMsg(null);
    }
}
  • 在Spring容器中发布事件
public static void main(String[] args) {
   SpringApplication application = new SpringApplication(SpringbootdemoApplication.class);
   //需要把监听器加入到spring容器中
   application.addListeners(new ApplicationListenerTest());
   Set<ApplicationListener<?>> listeners = application.getListeners();
   ConfigurableApplicationContext context =  application.run(args);
   //发布事件
   context.publishEvent(new ApplicationEventTest(new Object()));
   context.close();
}

上面的示例是在SpringBoot应用中简单的测试一下。

实际开发中实现监听还有其他的方式,在Spring框架中提供了两种事件监听的方式:

  1. 编程式:通过实现ApplicationListener接口来监听指定类型的事件

  2. 注解式:通过在方法上加@EventListener注解的方式监听指定参数类型的事件,写该类需要托管到Spring容器中

 在SpringBoot应用中还可以通过配置的方式实现监听:

   3. 通过application.properties中配置context.listener.classes属性指定监听器

下面分别分析一下这三种监听方式

编程式实现监听

实现ApplicationListenser接口:

@Component
public class ApplicationListenerTest implements ApplicationListener<ApplicationEventTest> {
    @Override
    public void onApplicationEvent(ApplicationEventTest event) {
        event.printMsg(null);
    }
}

控制台输出测试:

public static void main(String[] args) {
   SpringApplication application = new SpringApplication(SpringbootdemoApplication.class);
   //需要把监听器加入到spring容器中
   //application.addListeners(new ApplicationListenerTest());
   //Set<ApplicationListener<?>> listeners = application.getListeners();
   ConfigurableApplicationContext context =  application.run(args);
   //发布事件
   context.publishEvent(new ApplicationEventTest(new Object()));
}

那么我们跟踪一下源码,看一下事件是如何发布出去的,又是如何被监听到的呢?

AbstractApplicationContext.java中截取部分代码

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
   Assert.notNull(event, "Event must not be null");
   if (logger.isTraceEnabled()) {
      logger.trace("Publishing event in " + getDisplayName() + ": " + event);
   }

   // Decorate event as an ApplicationEvent if necessary
  //将object转成ApplicationEvent
   ApplicationEvent applicationEvent;
   if (event instanceof ApplicationEvent) {
      applicationEvent = (ApplicationEvent) event;
   }
   else {
      applicationEvent = new PayloadApplicationEvent<>(this, event);
      if (eventType == null) {
         eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
      }
   }

   // Multicast right now if possible - or lazily once the multicaster is initialized
   if (this.earlyApplicationEvents != null) {
      this.earlyApplicationEvents.add(applicationEvent);
   }
   else {
    // SimpleApplicationEventMulticaster 获取事件发布器,发布事件
      getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
   }

   // Publish event via parent context as well...
   if (this.parent != null) {
      if (this.parent instanceof AbstractApplicationContext) {
         ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
      }
      else {
         this.parent.publishEvent(event);
      }
   }
}

查看一下ApplicationContext类结构图可以发现:应用上下文AbstractApplicationContext实际还是通过继承ApplicationEventPublisher接口,实现了其中的事件发布的方法,使得Spring应用上下文有了发布事件的功能,在AbstractApplicationContext内部通过SimpleApplicationEventMulticaster事件发布类,将具体事件ApplicationEvent发布出去。

那么事件发布出去后又是如何被监听到的呢?下面看一下具Spring中负责处理事件发布类SimpleApplicationEventMulticaster 中multicastEvent方法具体实现过程

SimpleApplicationEventMulticaster.java部分代码,实际尝试将当前事件逐个广播到指定类型的监听器中(listeners已经根据当前事件类型过滤了)

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    // getApplicationListeners(event, type) 筛选监听器,在context.publish(ApplicationEvent event)中已经将事件传入,getApplicationListeners中将可以根据这个event类型从Spring容器中检索出符合条件的监听器

   for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      Executor executor = getTaskExecutor();
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
    //尝试逐个向监听器广播
         invokeListener(listener, event);
      }
   }
}

@EventListener注解方式实现

 定义注解方法

@Component
public class MyEventHandleTest {
    /**
     * 参数为Object类型时,所有事件都会监听到
     * 参数为指定类型事件时,该参数类型事件或者其子事件(子类)都可以接收到
     */
    @EventListener
    public void event(ApplicationEventTest event){
        event.printMsg(null);
    }

}

实现过程分析:

@EventListener注解主要通过EventListenerMethodProcessor扫描出所有带有@EventListener注解的方法,然后动态构造事件监听器,并将监听器托管到Spring应用上文中。

protected void processBean(
      final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) {

   if (!this.nonAnnotatedClasses.contains(targetType)) {
      Map<Method, EventListener> annotatedMethods = null;
      try {
        //查找含有@EventListener注解的所有方法
         annotatedMethods = MethodIntrospector.selectMethods(targetType,
               (MethodIntrospector.MetadataLookup<EventListener>) method ->
                     AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class));
      }
      catch (Throwable ex) {
         // An unresolvable type in a method signature, probably from a lazy bean - let's ignore it.
         if (logger.isDebugEnabled()) {
            logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex);
         }
      }
      if (CollectionUtils.isEmpty(annotatedMethods)) {
         this.nonAnnotatedClasses.add(targetType);
         if (logger.isTraceEnabled()) {
            logger.trace("No @EventListener annotations found on bean class: " + targetType.getName());
         }
      }
      else {
         // Non-empty set of methods
         ConfigurableApplicationContext context = getApplicationContext();
    //遍历含有@EventListener注解的方法
         for (Method method : annotatedMethods.keySet()) {
            for (EventListenerFactory factory : factories) {
               if (factory.supportsMethod(method)) {
                  Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName));
          //动态构造相对应的事件监听器
                  ApplicationListener<?> applicationListener =
                        factory.createApplicationListener(beanName, targetType, methodToUse);
                  if (applicationListener instanceof ApplicationListenerMethodAdapter) {
                     ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator);
                  }
          //将监听器添加的Spring应用上下文中托管
                  context.addApplicationListener(applicationListener);
                  break;
               }
            }
         }
         if (logger.isDebugEnabled()) {
            logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" +
                  beanName + "': " + annotatedMethods);
         }
      }
   }
}

在application.properties中配置context.listener.classes

添加如下配置:

context.listener.classes=com.sl.springbootdemo.Listeners.ApplicationListenerTest

查看一下DelegatingApplicationListener类中实现逻辑:

public class DelegatingApplicationListener
      implements ApplicationListener<ApplicationEvent>, Ordered {
   private static final String PROPERTY_NAME = "context.listener.classes";
   private int order = 0;
   //Spring framework提供的负责处理发布事件的类,前面说的Spring应用上下文中也是通过这个类发布事件的
   private SimpleApplicationEventMulticaster multicaster;
   @Override
   public void onApplicationEvent(ApplicationEvent event) {
      if (event instanceof ApplicationEnvironmentPreparedEvent) {
        // getListeners内部实现读取context.listener.classes配置的监听器
         List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
               ((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
         if (delegates.isEmpty()) {
            return;
         }
         this.multicaster = new SimpleApplicationEventMulticaster();
         for (ApplicationListener<ApplicationEvent> listener : delegates) {
            this.multicaster.addApplicationListener(listener);
         }
      }
    //发布事件
      if (this.multicaster != null) {
         this.multicaster.multicastEvent(event);
      }
   }

 Spring-boot-{version}.jar包中提供一个类DelegatingApplicationListener,该类的作用是从application.properties中读取配置context.listener.classes,并将事件广播给这些配置的监听器。通过前面一章对SpringBoot启动流程分析,我们已经了解到SpringBoot启动时会从META-INF/spring.factories中读取key为org.springframework.context.ApplicationListener的所有监听器。DelegatingApplicationListener的功能可以让我们不需要创建META-INF/spring.factories,直接在application.properties中配置即可。

【Spring Boot实战与进阶】自定义事件及监听 OverrideSystem.out.println(“接受到了事件:”+event.getClass());System.out.println(“接受到了事件:”+event.getSource());@OverrideSystem.out.println(“接受到了事件:”+event.getClass());自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。 阅读详情

相关推荐

Spring boot 实现监听 Redis key 失效事件

方式一:修改配置文件方式二:命令行开启。

Young Lee 3648

SpringBoot自定义事件监听

1.事件监听背景介绍 在spring中,事件监听机制主要涉及4个实现类。 ApplicationEvent:事件,每个实现类表示一类事件,可携带数据。抽象类。 ApplicationListener:事件监听器,用于接收事件处理时间。接口。 ApplicationEventMulticaster:事件管理者,可以添加/移除事件。用于事件监听器的注册和事件的广播。接口。 ApplicationEventPublisher:事件发布者,委托ApplicationEventMulticaster完成事件发布

jainszhang的博客 1897

Spring Boot事件驱动编程:使用ApplicationEvent实现事件监听(附代码示例)

本文介绍了Spring Boot中事件驱动编程的实现方法,重点讲解了如何使用ApplicationEvent进行事件的发布和监听。文章首先阐述了事件驱动编程的概念及其在Spring Boot中的应用原理,然后通过用户注册事件的示例,详细展示了自定义事件类、事件发布者和监听器的创建过程。同时提供了完整的代码实现和测试方法,并针对事件监听不触发的问题给出了排查建议。最后总结了学习要点并预告后续Spring Boot高级特性的内容,帮助开发者掌握松耦合的事件处理机制,提升系统可维护性和扩展性。

fykam的博客 778

(五)springboot实战——springboot自定义事件的发布和订阅

本节内容我们主要介绍一下springboot自定义事件的发布与订阅功能,一些特定应用场景下使用自定义事件发布功能,能大大降低我们代码的耦合性,使得我们应用程序的扩展更加方便。就本身而言,springboot的事件机制是通过观察者设计模式实现。通过ApplicationListener事件监听器实现事件的发布与订阅。我们以登录场景为例,假如用户登录之后,需要发送登录通知、发送邮件通知、发送签到通知,如果按照常规做法,我们可以顺序执行以上操作,但是使用springboot的事件机制,我们可以发布一个登录的事件消

厉害哥哥的博客 2381

Spring Boot 监听器详解

SpringApplicationRunListener 是SpringApplication 的运行监听器,提供Spring Boot启动时各个运行状态的监听,可以在应用程序启动的时候执行一些自定义操作或记录一些信息。SpringApplicationRunListener 在run中加载。是Spring 提供的上下文监听器,可用于监听指定感兴趣的事件。最后还是用一张图来总结整个流程作者其他文章:Prometheus 系列文章Prometheus 的介绍和安装。

分享技术干货和灵感、推荐新书和好玩的项目、分享Java面试题 8817

Qt绘图实战:用QGraphicsItem实现可拖拽箭头连接(附完整代码)

本文详细介绍了如何使用Qt的QGraphicsItem框架实现一个功能完备的可拖拽箭头连接组件。通过核心代码示例,讲解了如何创建自定义图形项、实现智能吸附、碰撞检测以及实时拖拽编辑路径,为构建流程图、拓扑图等专业图形编辑器提供了完整的解决方案。

m2n3b4v5c6的博客 626

SpringBoot 自定义事件

为什么80%的码农都做不了架构师?>>> ...

weixin_34357962的博客 320

LLC谐振变换器设计实战:从工作原理到参数设计与调试

开关电源设计是电力电子领域的核心技术,其核心目标在于提升效率与功率密度。为实现这一目标,软开关技术应运而生,它通过精心控制开关器件的电压与电流波形,使其在开通或关断瞬间实现零电压或零电流切换,从而从根本上降低开关损耗。LLC谐振变换器正是这一技术的杰出代表,它通过引入谐振网络,巧妙地实现了主开关管的零电压开关和次级整流管的零电流开关。这种拓扑结构在服务器电源、通信设备及高端显示驱动等要求高效率、高功率密度的应用场景中价值显著。本文将以半桥LLC为例,深入剖析其工作模态与增益特性,并系统阐述其参数设计、仿真验

weixin_34129696的博客 561

Spring Boot中使用监听器(六)

大家好,我是默语,一个专注于技术分享的博主。今天我们将深入探讨Spring Boot中使用监听器的各个方面。通过这篇文章,您将了解如何在Spring Boot项目中使用和自定义监听器,以便更好地处理各种事件。本文包含丰富的代码示例和详细的解释,确保您能够全面掌握监听器的使用技巧。让我们一起来学习吧!💡监听器是一种用于监听某些特定事件并对其进行响应的组件。这些监听器可以在应用程序的不同阶段(如启动、销毁、请求到达、会话创建等)执行特定的逻辑。

沉淀所学,分享所思,让热爱与成长同行。商务记录AI实战经验,助力开发者快速成长。 热爱AI,希望做出有影响力的技术成果。 技术点亮生活,分享连接价值与机会。 专注AI落地实战,陪你走好技术每一步。 1万+

鸿蒙OpenHarmony南向开发 轻量系统芯片移植指南(一)

OpenHarmony系统采用"系统>子系统>部件"层级架构,支持功能模块化裁剪。本文介绍了关键子系统及移植方法:1)启动恢复子系统负责内核到应用间的进程初始化,需配置启动入口标识及链接脚本;2)文件子系统提供基础文件操作接口,需适配HAL层文件读写功能,可通过Flash模拟、轻量文件系统或厂商自有方案实现。移植过程需修改config.json配置,添加对应组件定义及功能实现。系统采用模块化设计,开发者可根据实际需求灵活配置所需子系统功能。

yx525623的博客 1131

creo二次开发使用映射

在creo进行二次开发时,一些无法直接通过访问底层代码来对特征进行操作,比如“镜像装配”,这个时候就可以使用映射(Mapkey)来完成一键镜像。 注:这是镜像装配的代码 ProError status; ProMacro macro; wstring Macro; strMacro = L"mapkey(continued) ~ Command ProCmdMirrorAssem ; mapkey(continued) ~ Activate mirror_component_dialog Sy

qq_49328512的博客 1607

Spring Boot监听事件同步和异步使用

废话前言: 代码环境:WIN7+IDEA+JAD1.8+Spring Boot 2.0 首先说一下我为什么使用事件,比如现在创建一个订单但是我创建成功后要给客户发送一条短信和一个邮件提醒,本身没创建订单一系列操作就需要很多时间但是我还要去发送短信和邮件,期间还要调用其它服务来实现耗时比较长达不到客户的满意度,所以使用的方式可以说一下: 1:activeMQ(异步) 2:使用spring事件监听(同...

qq_30211955的博客 1万+

恶意代码实验3:Word宏病毒实验

只要下次打开这个word文档,就会执行以上代码,并将自身复制到Normal.dot(word文档的公共模板)和当前文档的ThisDocument中,同时改变函数名(模板中为Document_Close,当前文档为Document_Open),此时所有的word文档打开和关闭时,都将运行以上的病毒代码,可以加入适当的恶意代码,影响word的正常使用,本例中只是简单的跳出一个提示框。回答不正确三次,即可自动跳出病毒程序,但那时已经出现几十个文档。1、打开的宏编辑器如图所示,即可编写病毒代码。

qq_63949327的博客 6505

Spring Boot 事件机制详解

Spring Boot 事件机制详解

嗨,欢迎来到我的 优快云 博客小天地!一名深耕多年的技术发烧友。在这里,我将把日常工作中积累的宝贵经验,从复杂架构设计的精妙之处,到代码优化的实战技巧,毫无保留地分享给大家。 7252

Zoom AI 技术架构研究:联合式方法与多模态集成

通过 Zoom AI 开放平台,企业可以自定义 AI 模块 (如法律合规审查、客户反馈分析),扩展应用场景。这种开放平台策略使企业能够根据自身需求定制 AI 功能,满足特定业务需求。

shao.bing的专栏 1317

Python 中 dpkt 库的详细使用指南(强大的 Python 数据包解析库)

dpkt 是一个功能强大的 Python 网络数据包解析库,支持解析和构造以太网、IP、TCP/UDP 等多种协议的数据包。其核心功能包括解析各层协议头部、读写 pcap 文件、构造自定义数据包及分析 HTTP 流量等。dpkt 提供简单易用的 API,适用于网络分析、安全研究和流量监控场景。优化技巧包括数据包过滤、批量处理和选择性解析以提高性能,常见问题如数据不完整或协议识别错误可通过异常处理和字段验证解决。典型应用场景涵盖协议分析、网络调试和自定义数据包生成。

数据知道的博客 1万+

Spring及SpringBoot的事件监听案例Demo

一篇打通Spring事件机制:自定义事件、ApplicationListener与@EventListener两种监听方式,并详解SpringBoot六大启动事件触发时机,附完整代码与源码仓库,助你即学即用。

每个人都是独一无二的,把握好自己的节奏,跟着自己的心走。 1212

【数据湖仓】:Iceberg、Hudi 和 Paimon 对比

适用于需要多计算引擎支持和复杂查询的离线批处理场景。其中立性和灵活性使其成为构建新型数据平台的理想选择。:在需要高频数据更新和高效小文件管理的场景中表现出色,适合实时数据处理和增量数据更新的业务需求。:专为实时流式数据处理设计,适用于对数据实时性要求高的业务场景,如实时数据分析和实时指标监控。通过以上分析,可以看出 Apache Iceberg、Apache Hudi 和 Apache Paimon 各有其独特的优势和适用场景。企业应根据自身业务需求和技术栈选择合适的数据湖仓方案,以充分发挥其价值。

欢迎来到我的博客,一起探索代码里的世界! 1609

Spring Boot 事件和监听?

256 @Data81014 }15 }26912 System.out.println("监听到BlackListEvent事件: " + event.getAddress());

weixin_62421895的博客 980

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

spring boot2.x 自定义事件的发布与监听

一、前言 需要实现spring boot自定义事件的发布与监听,其实并没有多复杂,可以分以下三步进行: 通过继承抽象类ApplicationEvent,自定义事件; 通过实现 ApplicationListener接口 或者通过 @EventListener 注解到方法上,自定义一个事件的监听; 通过ApplicationContext对象,发布事件。 二、代码实现 创建一个spring boot项目,项目结构如下: 2. 导入maven依赖: <dependency>

Coder-文小白的博客 1868

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Spring Boot事件监听机制

当某件事情发生时,通知对此感兴趣的各方进行响应。报纸订阅:有新报纸时,报社会通知所有订阅者交通信号:红灯亮起时,车辆和行人会做出相应反应手机通知:收到消息时,手机会发出提示音在软件开发中,这种模式被称为观察者模式(Observer Pattern),也称为发布-订阅模式。事件触发时机ApplicationContext初始化或刷新完成时ApplicationContext启动时(调用start()方法)ApplicationContext停止时(调用stop()方法)

A1234543211232的博客 773

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

企业级spring-boot案例-Spring事件发布与监听

Spring事件发布与监听

ThinkWon的博客 2947

Spring listener——Spring boot实现监听器的两种方式

我们知道,在spring启动的过程中,会生成很多的监听器,监听整个spring容器的生命周期。那么,我们想要生成自己的listener需要怎么做呢?今天,就给大家带来spring boot实现监听器的两种方式。 自定义事件 自定义事件XiaoAMaCreatedEvent继承ApplicationEvent类 /** * [说明] * * @author xiaoama */ public class XiaoAMaCreatedEvent extends ApplicationEvent {

zxh1991811的博客 1万+

在Spring中使用监听器以及事件监听机制

在Spring中使用监听器以及事件监听机制

进击的豌豆的博客 1582

Spring Boot事件机制详解

事件驱动架构(Event-Driven Architecture, EDA)是一种软件设计模式,其中系统组件通过事件的发布与订阅进行通信。在Spring Boot中,事件机制为应用程序提供了松耦合的组件间通信方式,使得发布者无需关心谁在监听,监听者也无需了解事件来源

AWen_Jack的博客 1874
上一篇: 设计模式 - 单例模式(二)六种写法
下一篇: Arthas - Java 线上问题定位处理的终极利器
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仰望星空@脚踏实地

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值