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,一经查实,立即删除!

相关文章

JAVA基础(8) 面向对象编程3

目录 一、关键字static 1.概念 2.static关键字 &#xff08;1&#xff09;使用范围&#xff1a; &#xff08;2&#xff09;被修饰后的成员具备以下特点&#xff1a; 3.静态变量 &#xff08;1&#xff09;语法格式 &#xff08;2&#xff09;静态变量的特点 &#xf…

k8s-第五节-StatefulSet

StatefulSet StatefulSet 是用来管理有状态的应用&#xff0c;例如数据库。 前面我们部署的应用&#xff0c;都是不需要存储数据&#xff0c;不需要记住状态的&#xff0c;可以随意扩充副本&#xff0c;每个副本都是一样的&#xff0c;可替代的。 而像**数据库、Redis **这类…

CPU是什么?

CPU&#xff0c;全称Central Processing Unit&#xff0c;中文名为中央处理器&#xff0c;是计算机系统的核心部件&#xff0c;负责执行程序指令、处理数据以及控制计算机内部的其他组件。简单来说&#xff0c;CPU就像是计算机的大脑&#xff0c;负责进行所有的思考和计算工作。…

在Linux/Debian/Ubuntu中出现“Could not get lock /var/lib/dpkg/lock-frontend”问题的解决办法

在Linux/Debian/Ubuntu中出现“Could not get lock /var/lib/dpkg/lock-frontend”问题的解决办法 在使用 apt 或 apt-get 进行软件包管理时&#xff0c;有时会遇到以下错误提示&#xff1a; Could not get lock /var/lib/dpkg/lock-frontend - open (11: Resource temporari…

CCM的作用及原理

CCM调试的理论依据_ccm矩阵sat调试-CSDN博客 CCM是在WB之后&#xff0c;就是当AWB将白色校正之后其他颜色也会跟着有明显变化&#xff0c;CCM的作用就是要保持白色不变&#xff0c;把其他色彩校正到非常精准的地步。 校正后的颜色(target值是一个固定的值)CCM矩阵*原始的颜色…

代码随想录Day73(Part09)

badijkstar(堆优化版) 题目&#xff1a;47. 参加科学大会&#xff08;第六期模拟笔试&#xff09; (kamacoder.com) 思路&#xff1a;直接看答案 答案 import java.util.*;class Edge {int to; // 邻接顶点int val; // 边的权重Edge(int to, int val) {this.to to;this.val …

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

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

力扣139 单词拆分 Java版本

文章目录 题目描述代码 题目描述 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。 注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 示例 1&#xff1a…

HTTP与HTTPS的主要区别

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

堆和栈的区别及应用场景

堆和栈的区别及应用场景 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 在计算机科学和编程领域&#xff0c;堆&#xff08;Heap&#xff09;和栈&#xff08…

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

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

等保测评需要什么SSL证书

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

代码随想录Day76(图论Part11)

97.小明逛公园&#xff08;Floyd&#xff09; 题目&#xff1a;97. 小明逛公园 (kamacoder.com) 思路&#xff1a; 答案 import java.util.*;public class Main {public static void main(String[] args) {Scanner scanner new Scanner(System.in);int n scanner.nextInt();…

传统sql查询痛点及衍生的项目设计思路(设计一款可视化查询工具)

背景 最近三年&#xff0c;工作中很大一部分时间是写sql报表。业务很复杂&#xff0c;几十个表。常用的就有十几个。经常表连接达七八个。写得多了&#xff0c;我也很熟练了&#xff0c;但就是足够熟练了&#xff0c;我就越感觉有以下问题困扰我&#xff1a; 无法串联excel表…

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

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

序列化Serializable

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

Java中的设计模式在实际项目中的应用

Java中的设计模式在实际项目中的应用 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 设计模式是解决软件设计中常见问题的经验总结&#xff0c;它们提供了一种…

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;能…