Spring源码十一:事件驱动

上一篇Spring源码十:BeanPostProcess中,我们介绍了BeanPostProcessor是Spring框架提供的一个强大工具,它允许我们开发者在Bean的生命周期中的特定点进行自定义操作。通过实现BeanPostProcessor接口,开发者可以插入自己的逻辑,以增强或修改Bean的行为。这个接口在AOP、依赖注入和Bean管理等方面都有着广泛的应用。正确地使用BeanPostProcessor可以极大地提高Spring应用的灵活性和可扩展性。

通过上一篇文章的详细介绍,相信大家对BeanPostProcessor有了更深入的理解。在实际开发中,合理地应用BeanPostProcessor,可以帮助我们更好地控制和管理Bean的生命周期,实现复杂的业务需求。

接下来我们沿着上一篇的分析,回到refresh方法,接着往下看

initMessageSource

我们到initMessageSource方法中看下:

/*** Initialize the MessageSource.* Use parent's if none defined in this context.* 如果容器中已经注入id 为messageSource的bean* 如果没有,则初始化一个DelegatingMessageSource类型对象,注意一个细节,这里会将我初始化的Bean名称设置为messageSource* messageSource主要是用来处理国际化,就不继续讨论了*/protected void initMessageSource() {// 获取Spring beanFactory容器ConfigurableListableBeanFactory beanFactory = getBeanFactory();// 判断容器中,是否存id为messageSource的Beanif (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {// 获取messageSourcethis.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);// Make MessageSource aware of parent MessageSource.if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;if (hms.getParentMessageSource() == null) {// Only set parent context as parent MessageSource if no parent MessageSource// registered already.hms.setParentMessageSource(getInternalParentMessageSource());}}if (logger.isTraceEnabled()) {logger.trace("Using MessageSource [" + this.messageSource + "]");}}else {// Use empty MessageSource to be able to accept getMessage calls.// 初始化DelegatingMessageSourceDelegatingMessageSource dms = new DelegatingMessageSource();dms.setParentMessageSource(getInternalParentMessageSource());this.messageSource = dms;// 设置消息到容器中beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);if (logger.isTraceEnabled()) {logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");}}}

首先,`initMessageSource`方法的目的是确保Spring应用上下文(`ApplicationContext`)中有一个`MessageSource`组件。`MessageSource`是Spring国际化的核心接口,它提供了一种机制,允许应用程序根据用户的区域设置(Locale)来解析和提供相应的消息。

`MESSAGE_SOURCE_BEAN_NAME`是`AbstractApplicationContext`中定义的一个常量,其值为"defaultMessageSource"。这意味着,如果你要在XML配置文件中定义一个`MessageSource` bean,它的`id`属性必须设置为"defaultMessageSource",这样Spring容器才能正确地识别和获取它。

在`else`分支中,代码创建了一个`DelegatingMessageSource`实例。这是一个默认的`MessageSource`实现,它本身不包含任何消息,但可以作为一个代理(delegate),将消息解析委托给其父级`MessageSource`。如果没有任何`MessageSource`被定义,这个默认实例会被注册到Spring容器中,以避免在尝试解析消息时出现空指针异常。

国际化(i18n)是指应用程序能够适应并支持多种语言和文化。在软件开发中,这意味着用户界面、错误消息、日志信息等都应该能够以用户的本地语言和格式显示。Spring的`MessageSource`支持这一功能,它允许开发者定义不同语言环境的消息,并在运行时根据用户的`Locale`动态选择正确的消息。

虽然`MessageSource`在Spring中支持国际化,但在现代Java开发中,特别是使用Spring Boot时,国际化的处理方式可能会有所不同。Spring Boot提供了更简便的方式来管理资源和消息,例如使用`MessageSourceAutoConfiguration`和约定优于配置的原则。因此,直接使用Spring的`MessageSource`进行国际化可能不如使用Spring Boot的自动配置来得普遍。

总的来说,了解`MessageSource`的工作原理和配置方式是有价值的,但也要注意当前的最佳实践和趋势,特别是在使用现代Spring技术栈时。


ApplicationEventMulticaster

我们接着看refresh方法中的下一个方法

initApplicationEventMulticaster

我们进入initApplicationEventMulticaster方法中:

/*** Initialize the ApplicationEventMulticaster.* Uses SimpleApplicationEventMulticaster if none defined in the context.* @see org.springframework.context.event.SimpleApplicationEventMulticaster*/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 {this.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() + "]");}}}


在Spring框架中,`ApplicationEventMulticaster`是一个关键组件,负责管理和广播事件。`SimpleApplicationEventMulticaster`是`ApplicationEventMulticaster`的一个实现,它提供了基本的事件广播功能。


在Spring应用上下文初始化过程中,`initApplicationEventMulticaster`方法负责确保Spring容器中有一个`ApplicationEventMulticaster`的实例。这个实例可以通过检查Spring容器(`beanFactory`)来确定是否已经定义了一个名为`APPLICATION_EVENT_MULTICASTER_BEAN_NAME`(通常是"applicationEventMulticaster")的bean。如果存在,就直接获取并使用这个bean;如果不存在,就创建一个`SimpleApplicationEventMulticaster`的实例,并将其注册到Spring容器中。


`ApplicationEventMulticaster`与`ApplicationListener`密切相关。`ApplicationListener`是一个接口,任何实现了这个接口的bean都会被`ApplicationEventMulticaster`识别为监听器。当`ApplicationEventMulticaster`接收到一个`ApplicationEvent`(Spring框架中的事件对象)时,它会遍历所有注册的`ApplicationListener`,检查是否有监听器对这个事件感兴趣。

如果找到匹配的监听器,`ApplicationEventMulticaster`会调用监听器的`onApplicationEvent`方法来处理事件。这种设计模式被称为观察者模式,其中`ApplicationEventMulticaster`是主题(Subject),而`ApplicationListener`是观察者(Observer)。这种模式允许应用程序在发生特定事件时发布通知,而无需关心哪些组件会对此事件做出响应。


在现代的Spring应用程序中,事件驱动模型是一个强大的功能,它允许应用程序的不同部分通过发布和监听事件来进行解耦。例如,当一个服务完成了一个重要的业务操作时,它可以发布一个事件,而其他服务或组件可以监听这个事件并做出相应的处理,如更新缓存、发送通知等。这种模型提高了应用程序的灵活性和可扩展性。


示例

1. 自定义事件类

首先,定义一个自定义事件类MyselfEvent,继承自ApplicationEvent

import org.springframework.context.ApplicationEvent;public class MyselfEvent extends ApplicationEvent {private String message;public MyselfEvent(Object source, String message) {super(source);this.message = message;}public String getMessage() {return message;}public void event() {// 处理事件逻辑System.out.println("Event method called with message: " + message);}
}

2. 自定义监听器

接着,创建一个监听器MyselfListener,实现ApplicationListener<MyselfEvent>接口:

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class MyselfListener implements ApplicationListener<MyselfEvent> {@Overridepublic void onApplicationEvent(MyselfEvent event) {// 处理事件event.event();System.out.println("Received event with message: " + event.getMessage());}
}

3. 配置监听器(XML配置)

将监听器注册到Spring上下文中,可以使用XML配置:

<!-- applicationContext.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 配置自定义监听器 --><bean id="myselfListener" class="com.example.MyselfListener"/>
</beans>

4. 发布事件

在Spring上下文初始化后,通过publishEvent方法发布事件:

public class Main {public static void main(String[] args) {ApplicationContext context = new MyselfClassPathXmlApplicationContext("applicationContext.xml");JmUser jmUser = (JmUser)context.getBean("jmUser");MyselfEvent event = new MyselfEvent("source", "This is a custom event");context.publishEvent(event);//		System.out.println(jmUser.getName());
//		System.out.println(jmUser.getAge());}
}

5. 理解事件发布过程中的广播器作用

要深入理解事件发布过程中广播器ApplicationEventMulticaster的作用,可以跟踪publishEvent方法的执行过程。

ClassPathXmlApplicationContext类的publishEvent方法实际上是通过其父类AbstractApplicationContext实现的:

public abstract class AbstractApplicationContext extends DefaultResourceLoaderimplements ConfigurableApplicationContext, DisposableBean {@Overridepublic void publishEvent(ApplicationEvent event) {getApplicationEventMulticaster().multicastEvent(event);}@Nullableprotected ApplicationEventMulticaster getApplicationEventMulticaster() {return this.applicationEventMulticaster;}
}

getApplicationEventMulticaster方法返回一个ApplicationEventMulticaster实例,通常是SimpleApplicationEventMulticaster,用于将事件分发给已注册的监听器。

SimpleApplicationEventMulticastermulticastEvent方法中,事件会被分发给所有匹配的监听器:

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {@Overridepublic void multicastEvent(final ApplicationEvent event) {for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {listener.onApplicationEvent(event);}}
}

小结

通过以上步骤,我们实现了基于Spring内部广播器发布和处理自定义事件的过程,并深入理解了ApplicationEventMulticaster在事件发布中的关键作用。广播器负责管理和调用注册的监听器,从而实现事件驱动的编程模型。

总结

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

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

相关文章

昇腾910B部署Qwen2-7B-Instruct进行流式输出【pytorch框架】NPU推理

目录 前情提要torch_npu框架mindsport框架mindnlp框架 下载模型国外国内 环境设置代码适配&#xff08;非流式&#xff09;MainBranch结果展示 代码适配&#xff08;流式&#xff09; 前情提要 torch_npu框架 官方未适配 mindsport框架 官方未适配 mindnlp框架 官方适配…

HTTP与HTTPS的主要区别

HTTP&#xff08;超文本传输协议&#xff09;与HTTPS&#xff08;超文本传输安全协议&#xff09;的主要区别在于安全性、数据传输方式、默认使用的端口以及对网站的影响。 一、安全性&#xff1a; HTTP是一种无加密的协议&#xff0c;数据在传输过程中以明文形式发送&#x…

InfluxDB时序数据库基本使用介绍

1、概要介绍 1.1、时序数据库使用场景 所谓时序数据库就是按照一定规则的时间序列进行数据读写操作的数据库。它们常被用于以下业务场景&#xff1a; 物联网IOT场景&#xff1a;可用于IOT设备的指标、状态监控数据存取。IT建设场景&#xff1a;可用于服务器、虚拟机、容器的…

等保测评需要什么SSL证书

在进行信息安全等级保护&#xff08;简称“等保”&#xff09;测评时&#xff0c;选择合适的HTTPS证书对于确保网站的安全性和合规性至关重要。以下是在等保测评中选择HTTPS证书时应考虑的因素&#xff1a; 国产证书&#xff1a; 等保测评倾向于使用国产品牌的SSL证书&#x…

上网行为管理系统是什么?有哪些好用的上网行为管理系统?

IT经理&#xff08;ITM&#xff09;: 大家好&#xff0c;今天我们聚在这里&#xff0c;是为了讨论一个对我们公司来说越来越重要的议题&#xff1a;上网行为管理系统&#xff08;WBS&#xff09;。我们知道&#xff0c;员工的网络使用已经不仅仅是个人行为&#xff0c;它直接影…

序列化Serializable

一、传输对象的方式 将对象从内存传输到磁盘进行保存&#xff0c;或者进行网络传输&#xff0c;有两种方式&#xff1a; 实现Serializable接口&#xff0c;直接传输对象转成json字符串后&#xff0c;进行字符串传输 二、直接传输对象 implements Serializable Data Equal…

resp 无法连接 redis 服务器

问题原因可能是&#xff1a;防火墙 防火墙对这个端口没有开放&#xff0c;所以主机访问不到 解决方法&#xff1a; 步骤1&#xff1a;开发指定端口号 #放通6379/tcp端口 firewall-cmd --zonepublic --permanent --add-port6379/tcp 步骤2&#xff1a;重启防火墙 firewall-c…

.netcore微服务——项目搭建

在.NET Core中&#xff0c;微服务是一种架构风格&#xff0c;它将应用程序构造为一组小型服务的集合&#xff0c;这些服务都通过HTTP-based API进行通信。每个服务都是独立部署的&#xff0c;可以用不同的编程语言编写&#xff0c;并且可以使用不同的数据存储技术。 微服务的主…

什么是网络抓取|常见用例和问题

你可能听说过数据被称为现代信息社会的新石油。由于线上信息量庞大&#xff0c;能够有效地收集和分析网页数据已经成为企业、研究人员和开发人员的关键技能。这就是网页抓取技术的用武之地。网页抓取&#xff0c;也称为网页数据提取&#xff0c;是一种强大的技术&#xff0c;能…

IDEA 2018提交Git之后撤销commit

1、选择项目——>右击git——>找到Repostiory——>执行rest head 2、编辑reset head 3、回退到上一个版本&#xff08;HEAD~1&#xff09;&#xff0c;点击reset即可&#xff0c;如果还想继续回滚&#xff0c;再次执行即可

Linux平台x86_64|aarch64架构如何实现轻量级RTSP服务

技术背景 我们在做Linux平台x86_64架构或aarch64架构的推送模块的时候&#xff0c;有公司提出这样的技术需求&#xff0c;希望在Linux平台&#xff0c;实现轻量级RTSP服务&#xff0c;实现对摄像头或屏幕对外RTSP拉流&#xff0c;同步到大屏上去。 技术实现 废话不多说&…

在 Baklib Experience 中实现混合 CMS 架构

“还记得 CMS 主要用于在网页上布局内容吗&#xff1f;当时&#xff0c;这满足了网站管理需求。然而&#xff0c;行业正在发生变化&#xff0c;数字体验平台 Baklib Digital Content Experience 正在引领潮流。继续阅读以了解如何以及详细了解可用于确保全渠道成功的两个原则。…

python笔记和练习----少儿编程课程

第1课&#xff1a; 认识新朋友-python 知识点&#xff1a; 1、在英文状态下编写Python语句。 2、内置函数print()将结果输出到标准的控制台上&#xff0c;它的基本语法格式如下&#xff1a; print("即将输出的内容") #输出的内容要用引号引起来&#xff0c;可…

遗漏知识点

什么是RAII&#xff1f; RAII是Resource Acquisition Is Initialization&#xff08;wiki上面翻译成 “资源获取就是初始化”&#xff09;的简称&#xff0c;是C语言的一种管理资源、避免泄漏的惯用法。利用的就是C构造的对象最终会被销毁的原则。RAII的做法是使用一个对象&am…

DC/AC电源模块在不同的电源类型之间进行转换

BOSHIDA DC/AC电源模块在不同的电源类型之间进行转换 电力转换是现代社会不可或缺的一部分&#xff0c;它使我们能够在不同的电源类型之间进行转换&#xff0c;从而满足各种设备和应用的需求。DC/AC电源模块是一种用于将直流电转换为交流电的设备&#xff0c;它在电子设备、太…

[单master节点k8s部署]19.监控系统构建(四)kube-state-metrics

kube-state-metrics 是一个Kubernetes的附加组件&#xff0c;它通过监听 Kubernetes API 服务器来收集和生成关于 Kubernetes 对象&#xff08;如部署、节点和Pod等&#xff09;的状态的指标。这些指标可供 Prometheus 进行抓取和存储&#xff0c;从而使你能够监控和分析Kubern…

软件是什么?一个软件到底是哪些部分组成的-软件到底有哪些分支呢?

https://doc.youyacao.com/117/2163 软件是什么&#xff1f;一个软件到底是哪些部分组成的-软件到底有哪些分支呢&#xff1f; 何为软件 软件定义 的本质是通过软件编程实现硬件资源的虚拟化、灵活、多样和定制化功能&#xff0c;以最大化系统运行效率和能量效率。它基于硬…

VirtualBox的windows server 2016设置主机和虚拟机共享文件夹

文章目录 安装步骤1. windows server 2016安装增强功能2.上述安装完成之后&#xff0c;需要做共享文件夹&#xff0c;在宿主机&#xff0c;新建一个test文件夹&#xff0c;做共享设置&#xff0c;如下图&#xff1a;3.然后打开虚拟机&#xff0c;设置文件共享 安装步骤 1. win…

kafka系列之消费后不提交offset情况的分析总结

概述 每当我们调用Kafka的poll()方法或者使用KafkaListener(其实底层也是poll()方法)时&#xff0c;它都会返回之前被写入Kafka的记录&#xff0c;即我们组中的消费者还没有读过的记录。 这意味着我们有一种方法可以跟踪该组消费者读取过的记录。 如前所述&#xff0c;Kafka的一…

Java数据结构-树的面试题

目录 一.谈谈树的种类 二.红黑树如何实现 三.二叉树的题目 1.求一个二叉树的高度&#xff0c;有两种方法。 2.寻找二叉搜索树当中第K大的值 3、查找与根节点距离K的节点 4.二叉树两个结点的公共最近公共祖先 本专栏全是博主自己收集的面试题&#xff0c;仅可参考&#xf…