Spring源码十一:事件驱动

news2024/10/7 18:04:07

上一篇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的Bean
		if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
			// 获取messageSource
			this.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.
			// 初始化DelegatingMessageSource
			DelegatingMessageSource 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> {

    @Override
    public 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/beans
                           http://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 DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean {

    @Override
    public void publishEvent(ApplicationEvent event) {
        getApplicationEventMulticaster().multicastEvent(event);
    }

    @Nullable
    protected ApplicationEventMulticaster getApplicationEventMulticaster() {
        return this.applicationEventMulticaster;
    }
}

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

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

public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {

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

小结

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

总结

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

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

相关文章

ServiceImpl中的参数封装为Map到Mapper.java中查询

ServiceImpl中的参数封装为Map到Mapper.java中查询&#xff0c;可以直接从map中获取到key对应的value

吴恩达机器学习作业ex7:K 均值聚类和主成分分析(Python实现)详细注释

文章目录 1 K 均值聚类1.1 实施 K-means1.1.1 寻找最近的中心点1.1.2 计算中心点均值 1.2 示例数据集上的 K-means1.3 随机初始化1.4 用 K-means 压缩图像1.4.1 对像素进行 K 均值分析 2 主成分分析2.1 样例数据集2.3 利用 PCA 降低维度2.3.1 将数据投影到主成分上2.3.2 重建数…

满足GMSL静电防护要求的方案

什么是GMSL&#xff1f;它是做什么用的&#xff1f;它有什么优点&#xff1f;设计GMSL防静电有啥难度&#xff1f; 带着这些疑问我们先了解下什么是GMSL。 一&#xff0e;简述 GMSL GMSL&#xff08;Gigabit Multimedia Serial Link&#xff09;即千兆多媒体串行链路&#xf…

vs code 波浪线报错

这种红色波浪线的 VS code 报错&#xff0c;之前我都是直接忽略&#xff0c;因为不影响运行&#xff0c;但是我看着就很闹心想要给它去掉。 明明这个module 在啊&#xff0c;为啥一直报错 Cannot find module 今天知道原因了&#xff1a; 为了图方便&#xff0c;我 的 VS …

HPR3B-30A1-201、HPR3B-30A2-211-M4液压比例减压阀放大器

HANDOK HYDRAULIC比例减压阀HPR2P-30A1-201、HPR2P-30A1-201-M5、HPR3S-40A1-201-M3、HPR3Q-40A1-201-M2、HDPR3Q-40A1-201-M0、HPR3B-30A2-211、HPR3B-40F1-212 FOR SBS120/140、HDSV4B-A1-232、HPR3NB-30A-221、HDSV3B-A1-232-GO-PVD、HPR3B-30A1-213、HSVD3B-A1-232-GO-PSVD…

网络-calico问题分析

项目场景&#xff1a; calico-node日志提示 Failed to auto-detect host MTU - no interfaces matched the MTU interface pattern. To use auto-MTU, set mtuifacePattern to match your hosts’s interfaes. 同时&#xff0c;cali开头网卡的mtu是1440大小 原因分析&#xff…

每日复盘-20240705

今日关注&#xff1a; 20240705 六日涨幅最大: ------1--------300391--------- 长药控股 五日涨幅最大: ------1--------300391--------- 长药控股 四日涨幅最大: ------1--------300391--------- 长药控股 三日涨幅最大: ------1--------300391--------- 长药控股 二日涨幅最…

windows安装jdk21

下载 下载zip解压 设置环境变量 设置JAVA_HOME环境变量 Path环境变量添加如下值%HAVA_HOME%\bin 打开新的cmd&#xff0c;输入java --version查看效果

C++学习第十三天——stack/queue的使用及底层剖析双端队列容器适配器

✨ 少年的旅途应是星辰大海 &#x1f30f; &#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;C学习 &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&am…

安装Linux虚拟机

点击创建新的虚拟机 选择高级 系统自定义推荐 选择稍后安装 选择Linux 虚拟机命名并且选择创建位置 系统自定义 系统自定义推荐 系统自定义推荐 选择安装好的iOS文件 点击完成 选择编辑虚拟机设置 进入后选择第一个Install red hat enterprise 选择常用语言 设置…

【数据结构】(6.3)堆的应用——堆排序(C语言)

系列文章目录 文章目录 系列文章目录前言1. 堆排序的基础知识2. 堆排序详解2.1 堆排序整体思路2.2 思路详解2.2.1 建堆2.2.2 堆排序完整代码2.2.3 输出数据 3. 时间复杂度分析 前言 1. 堆排序的基础知识 堆排序&#xff08;Heap Sort&#xff09;就是对直接选择排序的一种改进…

springboot dynamic配置多数据源

pom.xml引入jar包 <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.2</version> </dependency> application配置文件配置如下 需要主要必须配置…

NET程序开发可能会用到的一些资料文档

NET程序开发使用的一些资料文件&#xff0c;NET高级调试&#xff0c;NET关键技术深入解析&#xff0c;WPF专业编程指南&#xff0c;程序员求职攻略&#xff0c;WPF编程宝典等。 下载链接&#xff1a;https://download.csdn.net/download/qq_43307934/89518582

c++重定向输出和输出(竞赛讲解)

1.命令行重定向 在命令行中指定输出文件 指令 .\重定向学习.exe > 1.txt 效果 命令行输入和输出 指令 .\重定向学习.exe < 2.txt > 1.txt 效果 代码 #include<bits/stdc++.h> using namespace std; int n; int main(){cin>>n;for(int i=0;i<n;i…

自动化设备上位机设计 二

目录 一 设计原型 二 后台代码 一 设计原型 二 后台代码 namespace 自动化上位机设计 {public partial class Form1 : Form{public Form1(){InitializeComponent();timer1.Enabled true;timer1.Tick Timer1_Tick;}private void Timer1_Tick(object? sender, EventArgs e)…

UrbanGPT: Spatio-Temporal Large Language Models

1.文章信息 本次介绍的文章是2024年arxiv上一篇名为《UrbanGPT: Spatio-Temporal Large Language Models》的文章&#xff0c;UrbanGPT旨在解决城市环境中的时空预测问题&#xff0c;通过大语言模型&#xff08;LLM&#xff09;的强大泛化能力来应对数据稀缺的挑战。 2.摘要 Ur…

Qt实现流动的管道效果代码示例

在现代图形用户界面&#xff08;GUI&#xff09;应用程序中&#xff0c;动态效果可以显著增强用户体验。本文将介绍如何使用Qt框架实现一个流动的管道效果。我们将通过自定义QWidget来绘制管道&#xff0c;并使用定时器来实现流动效果。 1. 准备工作 首先&#xff0c;确保你已…

【Linux进阶】磁盘分区2——MBR和GPT

1.磁盘的分区 因为如果你的磁盘被划分成两个分区&#xff0c;那么每个分区的设备文件名是什么&#xff1f; 在了解这个问题之前&#xff0c;我们先来复习一下磁盘的组成&#xff0c;因为现今磁盘的划分与它物理的组成很有关系。 我们谈过磁盘主要由碟片、机械手臂、磁头与主轴马…

计算机视觉 图像融合技术概览

在许多计算机视觉应用中(例如机器人运动和医学成像),需要将来自多幅图像的相关信息集成到一幅图像中。这种图像融合将提供更高的可靠性、准确性和数据质量。 多视图融合可以提高图像的分辨率,同时恢复场景的 3D 表示。多模态融合结合了来自不同传感器的图像,称为多传感器融…

【一念发动便是行】念头,就是命运

一个个恶念累积就是负能量&#xff0c;念头就是命运&#xff0c;克除恶念&#xff0c;防范念头&#xff0c;念头都有能量&#xff0c;学圣学须内外庄严检肃&#xff0c;言语有灵 多数人的问题都是出在念头上&#xff0c;念头&#xff0c;就是自己的命运&#xff1b; 当我们对自…