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.xdnf.cn/news/1473020.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

一文带你了解“商贸物流大脑”

商贸物流大脑源于实体物流&#xff0c;物理世界的实体物流是构建商贸物流大脑的基础。商贸物流大脑应该是物理世界的实际物流系统和相应的虚拟物流系统两个层面血肉相连、相互作用、有机统一的整体。商贸物流的研究内容包括数字产业化和物流数字化两大部分。信息产业化是进入物…

政务单位网站SSL证书选择策略

在数字化快速发展的今天&#xff0c;政务单位网站作为政府与公众沟通的重要桥梁&#xff0c;其安全性和可信度显得尤为重要。SSL证书作为保障网站安全的重要手段&#xff0c;其选择对于政务单位网站来说至关重要。本文将探讨政务单位网站在选择SSL证书时应该考虑的因素&#xf…

STM32入门笔记(03): ADC低通滤波(IIR)(SPL库函数版)(2)

A/D转换的常用技术有逐次逼近式、双积分式、并行式和跟踪比较式等。目前用的较多的是前3种。 A/D转换器的主要技术指标 转换时间 分辨率 例如&#xff0c;8位A/D转换器的数字输出量的变化范围为0&#xff5e;255&#xff0c;当输入电压的满刻度为5V时&#xff0c;数字量每变化…

PLM系统:PLM系统如何重塑产品生命周期管理

PLM系统&#xff1a;重塑产品生命周期管理的未来 在当今快速变化的商业环境中&#xff0c;产品生命周期管理&#xff08;PLM&#xff09;系统正逐渐成为企业提升竞争力、加速创新并优化运营流程的关键工具。随着技术的不断进步和市场需求的日益复杂化&#xff0c;传统的手动或…

直播预告 | VMware大规模迁移实战,HyperMotion助力业务高效迁移

2006年核高基专项启动&#xff0c;2022年国家79号文件要求2027年央国企100%完成信创改造……国家一系列信创改造政策的推动&#xff0c;让服务器虚拟化软件巨头VMware在中国的市场份额迅速缩水。 加之VMware永久授权的取消和部分软件组件销售策略的变更&#xff0c;导致VMware…

昇思25天学习打卡营第16天|文本解码原理——以MindNLP为例

在大模型中&#xff0c;文本解码通常是指在自然语言处理&#xff08;NLP&#xff09;任务中使用的大型神经网络模型&#xff08;如Transformer架构的模型&#xff09;将编码后的文本数据转换回可读的原始文本的过程。这些模型在处理自然语言时&#xff0c;首先将输入文本&#…

长沙(市场调研公司)源点 企业如何决定是否需要开展市场调研?

长沙源点调研咨询认为&#xff1a;对于一个特定问题&#xff0c;管理者在面临几种解决问题的方案时&#xff0c;不应该凭直觉草率开展应用性市场调研。事实上&#xff0c;首先需要做的决策是是否需要开展调研。在下述情况下&#xff0c;最好不要做调研&#xff1a; *缺乏资源。…

重大更新来袭!!《植物大战僵尸杂交版V2.1+修改器+融合版》

大家好&#xff01;每个软件更新总是令人兴奋不已。前段时间介绍的《植物大战僵尸》系列以其独特的策略玩法和丰富的植物角色&#xff0c;赢得了很多玩家的喜爱。而在今天&#xff0c;这款经典游戏全网最新版本——《植物大战僵尸&#xff1a;杂交版V2.1》正式推出&#xff0c;…

ASUS/华硕枪神4 G532L G732L系列 原厂win10系统 工厂文件 带F12 ASUS Recovery恢复

华硕工厂文件恢复系统 &#xff0c;安装结束后带隐藏分区&#xff0c;一键恢复&#xff0c;以及机器所有驱动软件。 系统版本&#xff1a;Windows10 原厂系统下载网址&#xff1a;http://www.bioxt.cn 需准备一个20G以上u盘进行恢复 请注意&#xff1a;仅支持以上型号专用…

【Redis】真行,原来是这样啊! --Redis自动序列化和手动序列化的区别(存储结构、内存开销,实际写法)

对于Redis有两种序列化和反序列化的方式&#xff0c; 方式一&#xff1a; 一种是通过 注入RedisTemplate 对象&#xff0c;找个对象&#xff0c;通过配置类进行一定的配置&#xff0c;使得使用RedisTemplate 对象时&#xff0c;便会使用配置的那些键、值的序列化方式&#xff…

有哪些有效的策略可以提升独立站的外链数量?

有哪些有效的策略可以提升独立站的外链数量&#xff1f;提升独立站的外链数量并不难&#xff0c;难得是不被谷歌惩罚把你的网站判定为作弊&#xff0c;正因如此&#xff0c;了解并应用GNB自然外链策略是个不错的开始&#xff0c;GNB外链的核心价值在于它提高了网站外链资源的自…

opencv概念以及安装方法

#opencv相关概念介绍 Open Source Computer Vision Library 缩写 opencv 翻译&#xff1a;开源的计算机视觉库 &#xff0c;英特尔公司发起并开发&#xff0c;支持多种编程语言&#xff08;如C、Python、Java等&#xff09;&#xff0c;支持计算机视觉和机器学习等众多算法&a…

Android车载开发中调试app与bat结合的丝滑小妙招

项目场景&#xff1a; 做Android车载的小伙伴调试app的时候常年就是手动adb命令三连&#xff0c;例如我常用的adb推送apk的命令 adb root adb remount adb push D:\workspace_atc\XSP3-10A\AutoSystemUIPlugin\app\release\CarSystemUI.apk /system/priv-app/CarSystemUI …

【qt】如何获取网卡的IP地址?

网卡相当于是一个翻译官,可以将数据转换成网络信号. 同时也可以将网络信号转换成数据. 我们要用到网卡类QNetmorkInterface 我们获取网卡的所有地址用静态函数allAddresses() 返回的还是一个QhostAddress的容器. QList<QHostAddress> addrList QNetworkInterface::allA…

相关技术 太阳能热水器循环水泵制作技术

网盘 https://pan.baidu.com/s/1oAKwUEGkKnEgxE-F4znKow?pwdidxd 双温区蓄能供热型太阳能热水系统及其工作方法.pdf 双罐叠压节能恒温型太阳能热水机组.pdf 基于傅科电流的循环式风能热水器.pdf 基于太阳能利用的建筑冷热电联产系统及工作方法.pdf 基于太阳能和热泵的双蓄式热…

剪画小程序:自媒体工具推荐:视频文案提取!

各位小伙伴&#xff0c;你们好啊&#xff01; 上周五观看《歌手 2024》第八期时&#xff0c;我再次被何炅老师幽默风趣的主持风格所折服。他的每一句话都仿佛带着魔力&#xff0c;让现场气氛热烈非凡&#xff0c;实在令人羡慕不已&#xff01; 何炅老师的口才之所以如此出色&a…

7月6日 VueConf 技术大会即将在深圳举办

7月6日&#xff0c;VueConf 2024 即将在深圳召开&#xff0c;本次大会正值 Vue.js 十周年&#xff0c;旨在聚焦 Vue.js 社区的成员&#xff0c;分享最新的技术动态、经验以及创新实践。 本次参与 VueConf 大会的是来自全球 Vue.js 核心团队成员、行业专家及前端开发者。其中&a…

# Sharding-JDBC从入门到精通(7)- Sharding-JDBC 公共表 与 读写分离

Sharding-JDBC从入门到精通&#xff08;7&#xff09;- Sharding-JDBC 公共表 与 读写分离 一、Sharding-JDBC 公共表 1、公共表 公共表属于系统中数据量较小&#xff0c;变动少&#xff0c;而且属于高频联合查询的依赖表。参数表、数据字典表等属于此类型。可以将这类表在每…

芯片基识 | 掰开揉碎讲 FIFO(同步FIFO和异步FIFO)

文章目录 一、什么是FIFO二、为什么要用FIFO三、什么时候用FIFO四、FIFO分类五、同步FIFO1. 同步FIFO电路框图2. 同步FIFO空满判断3. 同步FIFO设计代码4. 同步FIFO仿真结果 六、异步FIFO1、异步FIFO的电路框图2 、亚稳态3、打两拍4、格雷码5、如何判断异步FIFO的空满&#xff0…

外泌体相关基因肝癌临床模型预测——2-3分纯生信文章复现——4.预后相关外泌体基因确定单因素cox回归(2)

内容如下&#xff1a; 1.外泌体和肝癌TCGA数据下载 2.数据格式整理 3.差异表达基因筛选 4.预后相关外泌体基因确定 5.拷贝数变异及突变图谱 6.外泌体基因功能注释 7.LASSO回归筛选外泌体预后模型 8.预后模型验证 9.预后模型鲁棒性分析 10.独立预后因素分析及与临床的…