Spring事件分析以及多种使用方式实践 使用场景 附可执行demo

我们先说说它的特点,优缺点,以及使用场景,然后再说具体是怎么做的

Spring事件驱动的优点

  • 松耦合
    事件驱动模型通过发布-订阅机制促进组件间的解耦,发送者和接收者不需要直接知道对方的存在,只需关注事件本身,提高了系统的灵活性和可扩展性。

  • 可扩展性
    添加新的事件或监听器变得容易,只需实现相应的接口或继承类即可,不影响现有代码,有助于应对需求变化和系统升级。

  • 异步处理
    事件可以被异步处理,使得应用可以继续执行而不必等待事件处理完成,提升了响应速度和吞吐量。

  • 模块化
    支持模块化开发,不同的模块可以独立定义自己的事件和监听器,便于维护和复用。

  • 简化复杂交互
    对于多组件交互或复杂的业务流程,事件驱动模型提供了一种清晰的通信机制,降低了逻辑复杂度。

Spring事件驱动的缺点

  • 调试困难
    由于事件的异步和解耦特性,追踪事件的发布、传递和处理流程可能会比较困难,尤其是在分布式系统中。

  • 性能考量
    大量的事件监听器或频繁的事件发布可能会消耗较多资源,增加系统负担,影响性能。

  • 过度解耦的风险
    过度依赖事件驱动可能导致系统架构过于松散,难以理解各部分如何协作,增加了维护难度。

  • 不能用在分布式上面(一般分布式我们都用MQ)
    应用场景:

  • 异步处理
    如邮件发送、消息队列推送、日志记录等操作,可以异步执行不阻塞主线程。

  • 用户行为跟踪
    记录用户操作,如点击、登录、购买等,触发后续处理如统计分析、推荐系统更新等等。

  • 工作流引擎
    在工作流系统中,状态变更、任务完成等事件可以触发下一步动作,实现流程自动化。

  • 定时任务
    结合Spring的定时任务调度,事件可以按计划触发,执行定时处理逻辑。所以Spring事件驱动机制适用于需要解耦、异步处理或灵活扩展的场景,但也得注意潜在的管理和性能挑战,不能过度使用。


下面我们搞一搞Spring的事件
当我们去看Spring源码的时候自然而然会看到事件,Spring自身定义了好几种事件有不同的用途,咱们介绍下

Spring主要的内置事件驱动(Spring事件驱动)

ContextRefreshedEvent 上下文更新

ApplicationContext 被初始化或刷新时,该事件被发布。这也可以在 ConfigurableApplicationContext接口中使用 refresh() 方法来发生。此处的初始化是指:所有的Bean被成功装载后处理Bean被检测并激活,所有Singleton Bean 被预实例化,ApplicationContext容器已就绪可用。
在这里插入图片描述

ContextStartedEvent 上下文开始事件

当使用 ConfigurableApplicationContext (ApplicationContext子接口)接口中的 start() 方法启动 ApplicationContext 时,该事件被发布。你可以在接受到这个事件后重启任何停止的应用程序。

ContextStoppedEvent 上下文停止事件

当使用 ConfigurableApplicationContext 接口中的 stop() 停止 ApplicationContext 时发布这个事件。你可以在接受到这个事件后做必要的清理的工作

ContextClosedEvent 上下文关闭事件

当使用 ConfigurableApplicationContext接口中的 close()方法关闭 ApplicationContext 时,该事件被发布。一个已关闭的上下文到达生命周期末端,它不能被刷新或重启

RequestHandledEvent 请求处理事件

这是一个 web-specific 事件,告诉所有 bean HTTP 请求已经被服务。只能应用于使用DispatcherServlet的Web应用。在使用Spring作为前端的MVC控制器时,当Spring处理用户请求结束后,系统会自动触发该事件

除了上面介绍的事件以外,还可以通过扩展 ApplicationEvent 类来开发自定义的事件。

自定义事件(事件驱动)

我们可以定义一个事件类继承ApplicationEvent ,并设置为泛型,它毕竟是个类,我们可以在里面写点字段啊方法的都行,无非发布后在监听的地方去执行,那么具体你想搞些什么发布出去让 监听去做的,或者只是通知一声,都是你说了算

/*** 自定义事件 为什么自定义事件而不用ApplicationEvent?因为它不带泛型,传值只用Object不友好*/
public class CustomApplicationEvent<T> extends ApplicationEvent {//我们在事件中可以定义字段private String fieldTest;public CustomApplicationEvent(T source) {super(source);Thread thread = Thread.currentThread();System.out.println("Created a Custom event " +thread.getName());}public String getFieldTest(){return fieldTest;}public void setFieldTest(String fieldTest){this.fieldTest = fieldTest;}
}

自定义监听器都要继承ApplicationListener< E extends ApplicationEvent >,大家可以看到这个类的泛型有一个要求,就是必须要继承ApplicationEvent 的扩展事件类,这也就是为什么上面我们定义事件类的时候继承ApplicationEvent的原因

那么监听器实现有两种方式,并且支持同步异步,废话少说,上酸菜

  1. 使用@EventListener注解式,要监听哪个事件你就放到入参中
  2. 实现ApplicationListener<事件> 这个事件就是你自定义那个事件

/*** 监听器*/
@Component
public class CusEventListener {/*** 写法一*/@EventListenerpublic void handlerEvent(CustomApplicationEvent event) {System.out.println("listener handlerEvent……" + event.getSource());System.out.println("listener handlerEvent field……" + event.getFieldTest());}@Async@EventListenerpublic void handlerEvent2(CustomApplicationEvent event) {System.out.println("listener handlerEvent2……" + event.getSource());ThreadUtil.sleep(5000);System.out.println("listener handlerEvent2 field……" + event.getFieldTest());}/*** 写法二* 监听器1*/@Componentclass CustomEventListener implements ApplicationListener<CustomApplicationEvent> {@Overridepublic void onApplicationEvent(CustomApplicationEvent event) {Object source = event.getSource();//handle eventThread thread = Thread.currentThread();System.out.println("listener……" + thread.getName());}}/*** 监听器2*/@Componentclass CustomEvent2Listener implements ApplicationListener<CustomApplicationEvent> {@Overridepublic void onApplicationEvent(CustomApplicationEvent event) {Object source = event.getSource();//handle eventThread thread = Thread.currentThread();System.out.println("listener2……" + thread.getName());}}
}
@Autowired
private ApplicationContext applicationContext;@Override
public void publish(){Animal animal = new Animal();animal.setName("dog");CustomApplicationEvent event = new CustomApplicationEvent(animal);event.setFieldTest("我是事件中的字段");applicationContext.publishEvent(event);System.out.println("publish end");
}

你注意到没有,上面有个@Async就是异步的作用,但是怎么让它异步生效,还需要有个配置
配置类@Configuration @EnableAsync使异步生效,并且定义好线程池,异步就做到了

@Configuration
@EnableAsync
public class ExecutorPool {private static final Log log = LogFactory.get();private static final int CORE_POOL_SIZE = Runtime.getRuntime().availableProcessors() * 2;private static final int MAX_POOL_SIZE = CORE_POOL_SIZE * 2;@Bean("asyncExecutor")public ThreadPoolTaskExecutor asyncExecutor() {log.info("start asyncServiceExecutor : {}, {}", CORE_POOL_SIZE, MAX_POOL_SIZE);ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();//配置核心线程数executor.setCorePoolSize(CORE_POOL_SIZE);//配置最大线程数executor.setMaxPoolSize(MAX_POOL_SIZE);//配置队列大小executor.setQueueCapacity(2000);//配置线程池中的线程的名称前缀executor.setThreadNamePrefix("async-service-");// rejection-policy:当pool已经达到max size的时候,如何处理新任务// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//执行初始化executor.initialize();return executor;}
}

好了,此间茶话会到此结束,大家可以执行看看打印情况,有疑问请留言,翠花,捡桌子!

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

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

相关文章

【机器学习-06】Scikit-Learn机器学习工具包进阶指南:机器学习分类模型实战与数据可视化分析

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

[猫头虎分享21天微信小程序基础入门教程]第7天:小程序的权限与API使用

第7天&#xff1a;小程序的权限与API使用 &#x1f510; 自我介绍 大家好&#xff0c;我是猫头虎&#xff0c;一名全栈软件工程师。今天我们将继续微信小程序的学习&#xff0c;重点了解如何使用微信小程序的API&#xff0c;以及如何管理和请求小程序的权限。通过这些知识&am…

可视化:智慧能源解决方案,降本增效,运筹帷幄。

智慧能源可视化解决方案是一种利用先进的技术和工具&#xff0c;将能源数据以直观、可视的方式呈现出来&#xff0c;帮助企业更好地管理能源使用&#xff0c;降低成本&#xff0c;提高效率的解决方案。 以下是一些智慧能源可视化解决方案可以帮助企业降本增效、智连未来的方式&…

js前端获取农历日期

对于公历来说&#xff0c;直接 new 一个 Date 就能获取到&#xff0c;而对于农历来讲可就很难了&#xff0c;因为农历需要有许多复杂计算&#xff0c;虽然一般用的甚少&#xff0c;但对于某些场景来说还是会需要的&#xff0c;那么怎样获取农历日期呢&#xff1f; 这里推荐一个…

Linux:进程信号

生活角度的信号 a.信号在生活中&#xff0c;随时可以产生(信号的产生和我是异步的) b.你能认识这个信号 c.我们知道信号产生了&#xff0c;我能识别这个信号&#xff0c;信号该怎么处理 d.我们可能正在做着更重要的事情&#xff0c;把到来的信号暂不处理(1.我记得这个事 2.…

要不还是别搞Google Play了

​好消息&#xff1a;误导性条款合规了 坏消息: 应用被暂停了&#xff0c;太难玩了 5.13日收到邮件&#xff0c;被告知应用因为应用内体验问题被暂停上架了 邮件大意是由于违反执行流程政策(Violation of Enforcement Process policy)。 这个政策主要是讲Google Play会对账户/…

求四个整数中的最大值(函数)(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int a, b, c, d, max;//获取用户输入的数据&#xff1b;printf("请输入4个整数&#x…

你知道在 TS 中判断两个类型相等有多难吗?

公众号&#xff1a;程序员白特&#xff0c;欢迎一起交流学习~ TypeScript 中的类型相等 如果我们想判断两个变量是否相等&#xff0c;可以简单的通过 或 来进行比较&#xff0c;但是对比两个类型则不行。 在 TypeScript 中&#xff0c;类型是静态的&#xff0c;只会在编译时…

【Esp32S3 | Arduino】在Arduino中使用C++的高级特性

文章目录 前言一、Arduino中的Vector示例代码二、Arduino中的Map示例代码前言 最近在玩Arduino,自上次发现Arduino可以用Template,能使用高级宏后,这次发现Arduino竟可以使用C++中的一些STL容器,这属实令人震惊。起因是我打算做一个动态的数组,但是手动实现一些操作属实麻烦…

Hack The Box-SolarLab

总体思路 SMB获取敏感信息->CVE-2023-33733漏洞注入->CVE-2023-32315->敏感信息泄露 信息收集&端口利用 nmap -sSVC -p1-10000 10.10.11.16发现目标开放了80、135、139、445和6791端口&#xff0c;并且对应的端口也给出了重定向的标志&#xff0c;将域名加入到…

实验过程演示【计算机网络实验】

前言 这是陈旧已久的草稿2023-05-20 11:23:54 这个是计算机网络的一个实验&#xff0c;现在也不知道这个是啥来着。 现在2024-5-12 22:33:17&#xff0c;发布到[计算机网络实验]专栏中。 实验过程演示 2023-5-18 20:17:45 1&#xff0e;搭建一个多跳网络拓扑&#xff0c;…

算法题解记录25+++验证二叉搜索树(百日筑基)

题目描述&#xff1a; 难度&#xff1a;中等 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左 子树 只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必…

【MISRA-C-2012】:标准的理解与学习

标准的理解与学习 引用二、Misra-C 规则Misra-C全解读 - Rule 1 标准的C语言环境&#xff08;待更新&#xff09;Misra-C全解读 - Rule 2 未使用的代码&#xff08;待更新&#xff09;Misra-C全解读 - Rule 3 注释&#xff08;待更新&#xff09;Misra-C全解读 - Rule 4 字符与…

如何抠图?6个简单方便的抠图软件教你自己快速抠图

如何抠图&#xff1f;6个简单方便的抠图软件教你自己快速抠图 抠图是图像处理中常见的操作之一&#xff0c;它可以帮助我们从一幅图像中抠出特定的部分&#xff0c;通常用于制作合成图、更换背景或修改图像内容。下面介绍的6款简单方便的抠图软件可以帮助您快速进行抠图操作&a…

PyQt:界面无边框+实现窗口最小化(任务栏图标隐藏+托盘图标显示)

一、整体实现效果 诸如WX、各种管家的桌面显示方式。窗口关闭后&#xff0c;往往是任务栏图标消失&#xff0c;保持右下角托盘图标显示&#xff0c;保持后台运行。双击托盘图标后&#xff0c;窗口显示。 二、代码实现 from PyQt5.QtWidgets import * from ato_upgrade impo…

CSS常用滤镜效果

CSS 提供了多种滤镜效果&#xff0c;可以通过 filter 属性应用于 HTML 元素。以下是一些常用的 CSS 滤镜效果&#xff1a; 一、灰度 (Grayscale) 将图像转换为灰度图像。值在 0%&#xff08;原始图像&#xff09;和 100%&#xff08;完全灰度&#xff09;之间。 filter: gra…

【回溯 栈 代数系统 动态规划】282. 给表达式添加运算符

本文涉及知识点 回溯 栈 代数系统 动态规划 LeetCode 282. 给表达式添加运算符 给定一个仅包含数字 0-9 的字符串 num 和一个目标值整数 target &#xff0c;在 num 的数字之间添加 二元 运算符&#xff08;不是一元&#xff09;、- 或 * &#xff0c;返回 所有 能够得到 ta…

Ngnix VTS模块添加和测试

目录 VTS模块介绍 上传软件包xftp/lrzsz 执行脚本 添加vts的配置 测试 测试&#xff1a;nginx.conf配置文件是否有语法错误 测试&#xff1a;windows机器上访问效果 VTS模块介绍 Nginx VTS模块&#xff08;nginx Virtual Host Traffic Status Module&#xff09;是一个第三…

【C++初阶】string模拟实现

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅ ✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨ &#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1f33f;&#x1…

【精读Yamamoto】方向性连接如何丰富神经网络的功能复杂度 | 体外神经元培养实验 | 脉冲神经元模型(SNN) | 状态转移模型

探索大脑的微观世界&#xff1a;方向性连接如何丰富神经网络的功能复杂度 在神经科学领域&#xff0c;理解大脑如何通过其复杂的网络结构实现高级功能一直是一个核心议题。最近&#xff0c;一项由Nobuaki Monma和Hideaki Yamamoto博士领导的研究为我们提供了新的视角&#xff…