Spring实例化源码解析之Custom Events上集(八)

Events使用介绍

在ApplicationContext中,事件处理通过ApplicationEvent类和ApplicationListener接口提供。如果将实现ApplicationListener接口的bean部署到上下文中,每当一个ApplicationEvent被发布到ApplicationContext时,该bean将被通知。本质上,这是标准的观察者设计模式。官网地址

从Spring 4.2开始,事件基础设施得到了显著改进,并提供了基于注解的模型,以及发布任意事件的能力(即,并不一定要扩展自ApplicationEvent的对象)。当发布这样的对象时,我们会为您封装成一个事件。

下表描述了Spring提供的标准事件:

事件名称描述
ContextRefreshedEvent当ApplicationContext被初始化或刷新时发布。这通常发生在容器初始化完成并准备好接受请求时。
ContextStartedEvent当通过调用ApplicationContext的start()方法启动上下文时发布。
ContextStoppedEvent当通过调用ApplicationContext的stop()方法停止上下文时发布。
ContextClosedEvent当通过调用ApplicationContext的close()方法关闭上下文时发布。
RequestHandledEvent在Web应用程序中,当一个HTTP请求被处理完毕后发布。
ServletRequestHandledEvent在Web应用程序中,当一个HTTP请求被处理完毕后发布。它与RequestHandledEvent类似,但提供了更多与Servlet相关的信息。

这些标准事件提供了对应用程序上下文的生命周期和请求处理的跟踪和处理能力。您还可以定义和发布自定义事件,以满足应用程序的特定需求。以下示例显示了一个扩展 Spring 的 ApplicationEvent 基类的简单类:

package com.qhyu.cloud.springEvent;import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ApplicationContextEvent;import java.io.Serializable;/*** Title:BlockedListEvent <br>* Package:com.qhyu.cloud.springEvent <br>* @author piano <br>* date 2023年 10月08日 10:23 <br>* @version v1.0 <br>*/
public class BlockedListEvent extends ApplicationContextEvent implements Serializable {private static final long serialVersionUID = 1L;private final String address;private final String content;/*** Create a new ContextStartedEvent.* @param source the {@code ApplicationContext} that the event is raised for*               (must not be {@code null})*/public BlockedListEvent(ApplicationContext source, String address, String content) {super(source);this.address = address;this.content = content;}public String getAddress() {return address;}public String getContent() {return content;}
}

要发布自定义的ApplicationEvent,可以在ApplicationEventPublisher上调用publishEvent()方法。通常,可以通过创建一个实现ApplicationEventPublisherAware接口的类,并将其注册为Spring bean来完成这一操作。以下示例展示了这样一个类:

package com.qhyu.cloud.springEvent;import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;/*** Title:EmailService <br>* Package:com.qhyu.cloud.springEvent <br>* @author piano <br>* date 2023年 10月08日 10:28 <br>* @version v1.0 <br>*/
@Component
public class EmailService implements ApplicationEventPublisherAware, ApplicationContextAware {// 使用ApplicationEventPublisher应用事件发布器发布事件private ApplicationEventPublisher applicationEventPublisher;private ApplicationContext applicationContext;@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.applicationEventPublisher = applicationEventPublisher;}public void sendEmail(String address, String content) {applicationEventPublisher.publishEvent(new BlockedListEvent(applicationContext, address, content));}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext=applicationContext;}
}

在配置时,Spring容器检测到EmailService实现了ApplicationEventPublisherAware接口,并自动调用setApplicationEventPublisher()方法。实际上,传递的参数是Spring容器本身。您通过其ApplicationEventPublisher接口与应用程序上下文进行交互。

要接收自定义的ApplicationEvent,可以创建一个实现ApplicationListener接口的类,并将其注册为Spring bean。以下示例展示了这样一个类:

package com.qhyu.cloud.springEvent;import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;/*** Title:BlockedListNotifier <br>* Package:com.qhyu.cloud.springEvent <br>* @author piano <br>* date 2023年 10月08日 10:33 <br>* @version v1.0 <br>*/
@Component
public class BlockedListNotifier implements ApplicationListener<BlockedListEvent> {@Overridepublic void onApplicationEvent(BlockedListEvent event) {System.out.println("地址:"+event.getAddress());System.out.println("内容:"+event.getContent());}
}

结果如下:

在这里插入图片描述

请注意,ApplicationListener使用泛型参数化为您的自定义事件类型(在前面的示例中为BlockedListEvent)。这意味着onApplicationEvent()方法可以保持类型安全,避免了任何需要进行向下转型的情况。您可以注册任意数量的事件监听器,但请注意,默认情况下,事件监听器会同步接收事件。这意味着publishEvent()方法将会阻塞,直到所有监听器完成对事件的处理。这种同步和单线程的方法的一个优点是,当监听器接收到事件时,如果存在事务上下文,它将在发布者的事务上下文中运行。如果需要使用其他策略进行事件发布,例如默认情况下进行异步事件处理,请参阅Spring的ApplicationEventMulticaster接口和SimpleApplicationEventMulticaster实现的Javadoc,了解可应用于自定义"applicationEventMulticaster" bean定义的配置选项。

Spring的事件机制旨在实现在同一个应用程序上下文中的Spring bean之间进行简单通信。然而,对于更复杂的企业集成需求,独立维护的Spring Integration项目提供了完整的支持,用于构建基于轻量级、面向模式、事件驱动架构的解决方案,这些解决方案建立在众所周知的Spring编程模型之上。

源码解析

initApplicationEventMulticaster

initApplicationEventMulticaster是Spring框架中的一个方法,用于初始化应用程序事件广播器(ApplicationEventMulticaster)。

在Spring框架中,事件是通过应用程序事件广播器进行发布和传播的。当某个事件发生时,广播器负责将事件通知给对该事件感兴趣的监听器。

initApplicationEventMulticaster方法通常在Spring应用程序的上下文初始化过程中被调用。它的作用是创建并配置应用程序事件广播器,并将其注册到Spring上下文中。

具体来说,initApplicationEventMulticaster方法会执行以下任务:

  1. 创建应用程序事件广播器:根据配置和上下文环境,创建适当的应用程序事件广播器实例。在Spring中,通常使用SimpleApplicationEventMulticaster作为默认的事件广播器实现。

  2. 配置应用程序事件广播器:根据配置和需求,对应用程序事件广播器进行一些配置。例如,可以设置广播器的异步执行模式、任务执行器、异常处理器等。

  3. 注册应用程序事件广播器:将创建和配置好的应用程序事件广播器注册到Spring上下文中,以便在需要时可以使用。

通过初始化应用程序事件广播器,Spring框架可以实现事件驱动的编程模型。开发者可以定义自己的事件类,并编写监听器来处理这些事件。然后,通过应用程序事件广播器将事件传播给对应的监听器,从而实现解耦和模块间的协作。

需要注意的是,initApplicationEventMulticaster方法通常由Spring框架自动调用,开发者一般无需手动调用该方法。它是Spring容器内部的一个初始化过程,用于确保应用程序事件广播器的正确配置和注册。

protected void initApplicationEventMulticaster() {ConfigurableListableBeanFactory beanFactory = getBeanFactory();if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {this.applicationEventMulticaster =beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);if (logger.isTraceEnabled()) {logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");}}else {// 广播器的创建SimpleApplicationEventMulticasterthis.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);if (logger.isTraceEnabled()) {logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");}}}

registerListeners

registerListeners是Spring框架中的一个方法,用于向应用程序事件广播器(ApplicationEventMulticaster)注册监听器。

在Spring框架中,事件是通过应用程序事件广播器进行发布和传播的。监听器是用于接收和处理特定事件的组件。通过将监听器注册到应用程序事件广播器中,可以实现对事件的监听和响应。

registerListeners方法通常在Spring应用程序的上下文初始化过程中被调用。它的作用是将应用程序中定义的监听器注册到应用程序事件广播器中,使其能够接收和处理相应的事件。

具体来说,registerListeners方法会执行以下任务:

  1. 扫描应用程序上下文:遍历应用程序上下文中的所有Bean,查找实现了ApplicationListener接口的监听器Bean。

  2. 注册监听器:将扫描到的监听器Bean注册到应用程序事件广播器中,以便在事件发布时能够接收到相应的事件。

通过registerListeners方法,Spring框架可以自动将监听器注册到应用程序事件广播器中,无需手动编写注册代码。这样,当某个事件发生时,应用程序事件广播器会自动将事件通知给已注册的监听器,从而触发监听器中定义的处理逻辑。

需要注意的是,registerListeners方法通常由Spring框架自动调用,开发者无需手动调用该方法。它是Spring容器内部的一个初始化过程,用于自动注册监听器。开发者只需要实现相应的监听器接口,然后在Spring配置中声明监听器的Bean,即可实现对事件的监听和处理。

protected void registerListeners() {// Register statically specified listeners first.for (ApplicationListener<?> listener : getApplicationListeners()) {getApplicationEventMulticaster().addApplicationListener(listener);}// Do not initialize FactoryBeans here: We need to leave all regular beans// uninitialized to let post-processors apply to them!String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);for (String listenerBeanName : listenerBeanNames) {getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);}// Publish early application events now that we finally have a multicaster...Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;this.earlyApplicationEvents = null;if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {for (ApplicationEvent earlyEvent : earlyEventsToProcess) {getApplicationEventMulticaster().multicastEvent(earlyEvent);}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/97326.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用企业订货系统后的效果|软件定制开发|APP小程序搭建

使用企业订货系统后的效果|软件定制开发|APP小程序搭建 企业订货系统是一种高效的采购管理系统&#xff0c;它可以帮助企业更好地管理采购流程&#xff0c;降低采购成本&#xff0c;提高采购效率。 可以帮助企业提高销售效率和降低成本的软件工具。使用该系统后&#xff0c;企业…

如何使用 Tensor.art 实现文生图

摘要&#xff1a;Tensor.art 是一个基于 AI 的文本生成图像工具。本文介绍了如何使用 Tensor.art 来实现文生图的功能。 正文&#xff1a; 文生图是指将文本转换为图像的技术。它具有广泛的应用&#xff0c;例如在广告、教育和娱乐等领域。 Tensor.art 是一个基于 AI 的文本…

【SA8295P 源码分析】103 - QNX DDR RAM 内存布局分析

【SA8295P 源码分析】103 - QNX DDR RAM 内存布局分析 一、SA8295P QNX RAM 内存布局 (16G DDR)1.1 DDR 汇总描述1.2 QNX Meta reserved memory, DDR Rank01.3 Reserved for qnx1.4 Android GVM SysRam 相关内存(可修改)1.5 Reserved for qnx(不要修改)1.6 QNX SysRam 相关内…

强制删除文件?正确操作方法分享!

“我昨天在删除文件时有个文件一直删除不掉。想用强制删除的方法来把它删掉&#xff0c;应该怎么操作呢&#xff1f;谁能教教我呀&#xff1f;” 在使用电脑的过程中&#xff0c;我们有时候可能会发现文件无论怎么删除都无法删掉&#xff0c;如果我们想要强制删除文件但不知道怎…

Leetcode hot 100之回溯O(N!):选择/DFS

目录 框架&#xff1a;排列/组合/子集 元素无重不可复选 全排列 子集 组合&#xff1a;[1, n] 中的 k 个数 分割成回文串 元素无重不可复选&#xff1a;排序&#xff0c;多条值相同的只遍历第一条 子集/组合 先进行排序&#xff0c;让相同的元素靠在一起&#xff0c;如…

前端代码格式化规范总结

在日常开发过程中&#xff0c;经常会碰到代码格式化不一致的问题&#xff0c;还要就是 js 代码语法错误等没有及时发行改正&#xff0c;下面就介绍一下如何使用eslint、prettier、husky、lint-staged、commitizen来规范代码格式和提高代码质量的方法。 目录 准备工作代码检测代…

VMProtect使用教程(VC++MFC中使用)

VMProtect使用教程(VCMFC中使用) VMProtect是一种商业级别的代码保护工具&#xff0c;可以用于保护VC MFC程序。以下是使用VMProtect保护VC MFC程序的步骤&#xff1a; 1. 下载并安装VMProtect,C包含库及目录。 2. 在VC MFC项目中添加VMProtectSDK.h头文件&#xff0c;并在需…

Photoshop 笔记

目录 1. Photoshop 笔记1.1. 创建 A4 大小图片 1. Photoshop 笔记 1.1. 创建 A4 大小图片 Photoshop 的高版本自带了 A4、A5、A3、B5、B4、B3、C4、C5 等, 也可以直接制作打印美国信纸尺寸、法律文件用低、小报用纸等。 方法是: 新建 > 打印, 然后选择就可以了。 如果使…

Android ncnn-android-yolov8-seg源码解析 : 实现人像分割

1. 前言 上篇文章&#xff0c;我们已经将人像分割的ncnn-android-yolov8-seg项目运行起来了&#xff0c;后续文章我们会抽取出Demo中的核心代码&#xff0c;在自己的项目中&#xff0c;来接入人体识别和人像分割功能。 先来看下效果&#xff0c;整个图像的是相机的原图&#…

番外--Task2:

任务&#xff1a;root与普通用户的互切&#xff08;区别&#xff09;&#xff0c;启动的多用户文本见面与图形界面的互切命令&#xff08;区别&#xff09;。 输入图示命令&#xff0c;重启后就由图形界面转成文本登录界面&#xff1b; 输入图示命令&#xff0c;重启后就由文本…

java实验(头歌)--类的继承以及抽象类的定义和使用

文章目录 第一题第二题第三题 第一题 import java.awt.*; import java.awt.geom.AffineTransform; import java.awt.geom.PathIterator; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.Scanner;//把main 函数的给替换了 public static vo…

MybatisPlus01

MybatisPlus01 1.MybatisPlus初体验 1.1首先要引入MybatisPlus的依赖 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version></dependency>1.2定义Mapp…

es官方为我们提供的堆内存保护机制-熔断器( breaker )

总熔断器&#xff08;相当于似乎总闸&#xff09; 参数&#xff1a; indices.breaker.total.use_real_memory 默认值&#xff1a;true 在 elasticsearch.yml中配置。 参数&#xff1a; indices.breaker.total.limit 如果 indices.breaker.total.use_real_memory : true, in…

Java网络编程入门指南:实现一个多人聊天室

java网络&#xff1a;实现一个多人聊天室 Socket编程Socket基础TCP和UDP 服务器-客户端通信创建服务器创建客户端 HTTP通信HTTP请求HTTP响应 RMI远程方法调用创建RMI服务创建RMI客户端 多人聊天室 简介 Java网络编程是一种通过网络连接和通信来实现应用程序之间数据传输的技术。…

【JavaEE初阶】 Thread类及常见方法

文章目录 &#x1f334;Thread类的概念&#x1f333;Thread 的常见构造方法&#x1f384;Thread 的几个常见属性&#x1f340;start()-启动一个线程&#x1f332;中断一个线程&#x1f6a9;实例一&#x1f6a9;实例二&#x1f6a9;实例三 &#x1f38d;join()-等待一个线程&…

想要开发一款游戏, 需要注意什么?

开发一款游戏是一个复杂而令人兴奋的过程。游戏开发是指创建、设计、制作和发布电子游戏的过程。它涵盖了从最初的概念和创意阶段到最终的游戏发布和维护阶段的各个方面。 以下是一些需要注意的关键事项&#xff1a; 游戏概念和目标&#xff1a; 确定游戏开发的核心概念和目标…

【SpringBoot】| Thymeleaf 模板引擎

目录 Thymeleaf 模板引擎 1. 第一个例子 2. 表达式 ①标准变量表达式 ②选择变量表达式&#xff08;星号变量表达式&#xff09; ③链接表达式&#xff08;URL表达式&#xff09; 3. Thymeleaf的属性 ①th:action ②th:method ③th:href ④th:src ⑤th:text ⑥th:…

TCP相关面试题

TCP相关面试题 题目1 介绍一下TCP三次握手的过程 介绍TCP三次握手应该从3个方面进行回答&#xff0c;分别是数据包名称&#xff0c;客户端与服务端的状态变化&#xff0c;数据包的序号变化。而不能只是简单回答发送的数据包名称。 TCP三次握手的过程如下&#xff1a; 从数据…

vue3通过ref获取子组件defineExpose的数据和方法

1. 父组件: <script setup> import { defineAsyncComponent, watchEffect, toRefs, reactive } from vue;// 异步组件 const Test defineAsyncComponent(()>import(./xx/Test.vue))const child1Ref ref(null) const state reactive({age: 1,name: 2,sayHello: nul…

NSSCTF [BJDCTF 2020]easy_md5 md5实现sql

开局一个框 啥都没有用 然后我们进行抓包 发现存在提示 这里是一个sql语句 看到了 是md5加密后的 这里也是看了wp 才知道特殊MD5 可以被识别为 注入的万能钥匙 ffifdyopmd5 加密后是 276F722736C95D99E921722CF9ED621C转变为字符串 后是 or6 乱码这里就可以实现 注入 所…