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

news2024/9/23 15:31:47

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;

	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		this.applicationEventPublisher = applicationEventPublisher;
	}

	public void sendEmail(String address, String content) {
		applicationEventPublisher.publishEvent(new BlockedListEvent(applicationContext, address, content));
	}

	@Override
	public 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> {

	@Override
	public 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 {
			// 广播器的创建SimpleApplicationEventMulticaster
			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() + "]");
			}
		}
	}

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.coloradmin.cn/o/1075247.html

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

相关文章

Android Studio版本升级后的问题 gradle降级、jdk升级

Cannot use TaskAction annotation on method IncrementalTask.taskAction$gradle_core() because interface org.gradle.api.tasks.incremental.IncrementalTaskInputs is not a valid parameter to an action method. 修改下面两处地方分别为7.0.3、7.3.3Android Gradle plu…

Nginx的跨域问题解决

同源策略 浏览器的同源策略&#xff1a;是一种约定&#xff0c;是浏览器最核心也是最基本的安全功能&#xff0c;如果浏览器少了同源策略&#xff0c;则浏览器的正常功能可能都会受到影响。 同源: 协议、域名(IP)、端口相同即为同源 跨域问题 有两台服务器分别为A,B,如果从…

网络安全(自学黑客技术)——黑客学习方法

如果你想自学网络安全&#xff0c;首先你必须了解什么是网络安全&#xff01;&#xff0c;什么是黑客&#xff01;&#xff01; 1.无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面性&#xff0c;例如 Web 安全技术&#xff0c;既有 Web 渗透2.也有 Web 防…

MySQL运维—从零到放弃

1. 日志 1.1 错误日志 错误日志是 MySQL 中最重要的日志之一&#xff0c;它记录了当 mysqld 启动和停止时&#xff0c;以及服务器在运行过程中发生任何严重错误时的相关信息。当数据库出现任何故障导致无法正常使用时&#xff0c;建议首先查看此日志。 该日志是默认开启的…

JVM完整图文学习笔记 (含拓展知识广度学习) 第三章: 类加载与字节码技术

目录 编译期处理——语法糖 默认构造器 自动拆装箱 泛型集合取值 可变参数 foreach循环 switch 字符串 switch 枚举 枚举类 try-with-resources 方法重写时的桥接方法 匿名内部类 类加载阶段&#xff08;重点&#xff01;&#xff09; 加载 链接 &#xff08;1&#xff09;验证…

pip 清华镜像

python -m pip install --upgrade pip pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple pypi | 镜像站使用帮助 | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror

大数据—数据透析表常见使用(手把手详解)

我的个人主页&#xff1a;☆光之梦☆_C语言基础语法&#xff08;超详细&#xff09;,【java入门】语法总结-CSDN博客 创作不易&#xff0c;如果能帮到你就好 注&#xff1a;你的 &#x1f44d;点赞 ⭐收藏 &#x1f4dd;评论 是对博主最大的支持与鼓励喔 目录 一、创建数据透…

CentOS系统/root根目录扩容(扩展逻辑卷)

具体操作步骤 1、查看本机磁盘环境挂载情况 2、添加磁盘分区 3、开始扩容 4、同步到文件系统 1、查看本机磁盘环境挂载情况 [rooticon ~]# df -lh 可以看到/dev/mapper/centos-root 路径下容量为50G&#xff0c;我们要给这个路径下的容量扩容&#xff1a;[rooticon ~]# lsblk…

el-table 边框颜色修改 简单有效!

废话不多说&#xff0c;直接上图 &#xff08;1&#xff09;修改前的图如下&#xff1a; 以上是elementUI原组件自带的样式 &#xff08;2&#xff09;下面是修改后的边框图如下&#xff1a; 源码如下&#xff1a; <el-table :data"jctableData" border size…

mysql 逻辑备份 bin-log日志恢复

一、逻辑备份 逻辑备份&#xff1a;备份的是建表&#xff0c;建库&#xff0c;插入数据等操作所执行SQL语句&#xff0c;适用于中小型数据库&#xff0c;效率相对较低&#xff0c;提供三种级别的备份&#xff0c;表级&#xff0c;库级和全库级。 本质&#xff1a;导出的是SQL语…

基于Springboot实现疫情网课管理系统项目【项目源码+论文说明】分享

基于Springboot实现疫情网课管理系统演示 摘要 随着科学技术的飞速发展&#xff0c;各行各业都在努力与现代先进技术接轨&#xff0c;通过科技手段提高自身的优势&#xff1b;对于疫情网课管理系统当然也不能排除在外&#xff0c;随着网络技术的不断成熟&#xff0c;带动了疫情…

麻省理工学院与Meta AI共同开发StreamingLLM框架,实现语言模型无限处理长度

&#x1f989; AI新闻 &#x1f680; 麻省理工学院与Meta AI共同开发StreamingLLM框架&#xff0c;实现语言模型无限处理长度 摘要&#xff1a;麻省理工学院与Meta AI的研究人员联合研发了一款名为StreamingLLM的框架&#xff0c;解决了大语言模型在RAM与泛化问题上的挑战&am…

一用就会的手机配音软件,效果好到你震惊~

作为当今社交媒体时代的一员&#xff0c;我们经常需要在各种场合中使用配音软件&#xff0c;无论是自制视频内容还是进行个人创作&#xff0c;一款好用的配音软件真的很重要。所以经过小编这几天的努力&#xff0c;终于选出了一款备受好评的免费配音软件&#xff0c;不仅功能强…

高效数据传输:Java通过绑定快速将数据导出至Excel

摘要&#xff1a;本文由葡萄城技术团队原创并首发。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 把数据导出至 Excel 是很常见的需求&#xff0c;而数据的持久化&#xff0c;往往又放在…

为什么选择HubSpot电子邮件营销?

在数字时代&#xff0c;电子邮件营销是企业吸引、互动和保留客户的关键工具之一。然而&#xff0c;要在竞争激烈的市场中脱颖而出&#xff0c;并确保你的消息被准确地传达给目标受众&#xff0c;需要一款强大而智能的电子邮件营销平台。这就是HubSpot电子邮件营销背后的核心理念…

聊聊分布式架构06——[NIO入门]简单的Netty NIO示例

目录 Java NIO和Netty NIO比较 Java NIO&#xff1a; Netty&#xff1a; Netty NIO中的主要模块 Transport&#xff08;传输层&#xff09; Buffer&#xff08;缓冲区&#xff09; Codec&#xff08;编解码器&#xff09; Handler&#xff08;处理器&#xff09; Even…

王杰C++day3

#include <iostream>using namespace std;class Per { private:string name;int age;int *height;int *weight; public://有参构造函数Per(string n,int a,int h,int w):name(n),age(a),height(new int(h)),weight(new int(w)){cout << "p有参" <<…

Godot2D角色导航-自动寻路教程(角色随鼠标移动)

文章目录 运行结果2D导航概述开始前的准备2D导航创建导航网格创建角色 其他文章 运行结果 2D导航概述 Godot为2D和3D游戏提供了多个对象、类和服务器&#xff0c;以便于基于网格或基于网格的导航和路径查找。 说到导航&#xff0c;就得说一下导航网格&#xff0c;导航网格定义…

miRNA测序数据生信分析——第一讲,总结概述

miRNA测序数据生信分析——第一讲&#xff0c;总结概述 miRNA测序数据生信分析——第一讲&#xff0c;总结概述1. miRNA提取建库测序2. miRNA的生物学功能3. miRNA的生信分析模块3.1 miRNA鉴定3.2 miRNA表达量计算和差异表达miRNA分析3.3 miRNA靶基因注释3.4 另一个miRNA生信分…

Bridge

Bridge 动机 由于某些类型的固有的实现逻辑&#xff0c;使得它们具有两个变化的维度&#xff0c;乃至多个纬度的变化如何应对这种“多维度的变化”&#xff1f;如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化&#xff0c;而不引入额外的复杂度&#xff1…