coldsmog开发笔记
JS 事件笔记
Ckeditor 上传WPS图片失败问题
Springboot
SpringBoot 统一异常处理
Springboot 引入外部jar包
Springboot 打成war包
Springboot 多环境配置
SpringBoot @Scope注解学习
Springboot 快速生成项目API文档
SpringCache 缓存
Spring jetcache 二级缓存
Springboot 按条件装配类
FastJson的JsonPath语法
正则表达式语法
Spring 路径匹配
Feign 基础数据操作
监控Feign调用metrics
Springboot feign的性能优化
Jackson 设置序列化属性
SpringBoot 集成 Spring Data Mongodb 操作 MongoDB
MongoDB 的一些注意事项
MongoDB 指令对比
Jackson 解析XML
Springboot Redis注册
SpringBoot RedisTemplate批量插入
Springboot 指标监控Micrometer
springboot validation 注解校验
springboot 引入配置
Springboot 静态文件处理
Springboot 导出csv文件
Springboot 事件驱动(发布/订阅模式)
Springboot 启动过程和扩展点
Springboot 优化停机上下线
Spring自动装配 - 干饭角度学习
Springboot ShardingJDBC
Springboot的重试
springboot 动态修改端口
Oracle
Oracle 中实现自增ID
Oracle 定时任务
Oracle 解锁临时表
Oracle 检查连接数
Oracle 表空间
Oracle 解释执行SQL
markdown作图(适用typora)
服务器压测
业务对象层和数据层
并发限流处理
中间件
Yarn的使用
Dubbo学习笔记-RPC扩展和本地Mock
Dubbo学习笔记-泛化实现进行mock
Redis缓存穿透,缓存击穿,缓存雪崩
Galera 集群说明
Pip 镜像
pip 使用
MySQL命令行
数据库缓存双写方案
Git相关操作
Redis 操作时间复杂度一览
nacos 杂记
mybatis 散记
shardingjdbc
一次线上事故排查发现的Caffeine缓存死锁问题
设计模式
重新讲讲单例模式和几种实现
更优雅地实现策略模式
Http-headers
Prometheus 杂散笔记
JAVA 散记
CompletableFuture
Gson、FastJson、Jackson、json-lib对比总结
jackson 时间的序列化踩坑
JVM
自定义注解
mysql类型和java类型 转换一览表
枚举维护一个Map<value, Enum>的映射
Java中String +、concat、StringBuilder、StringBuffer 性能对比
TraceId 使用
MySQL 多数据源处理
Mybatis-plus 流式查询
JAVA发送win 桌面通知
idea 启动项目失败非代码问题杂记
Lambda 简述
Arthas 使用笔记
一种链式更新数据的数据模式
Skywalking 新增中间件插件
Redission 使用
数据导出为图片
IDEA 的热重启
Netty 工具类
maven 插件
本文档使用 MrDoc 发布
-
+
首页
Springboot 事件驱动(发布/订阅模式)
Spring的事件监听(也叫事件驱动)是观察者模式的一种实现,只要是观察者模式,就含有主题(针对该主题的事件),发布者(发布主题或事件),订阅者(监听主题的人)。有三个部分组成,事件(ApplicationEvent)、监听器(ApplicationListener)和事件发布操作。 作用: **使用事件机制我们可以将相互耦合的代码解耦,从而方便功能拓展和调整。** #### 1. 观察者模式简介 当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。 比如,当一个对象被修改时,则会自动通知它的依赖对象。观察者模式属于行为型模式。 ![img](https://coldsmog.cn/media/202209/2022-09-27_153135_xtfmcqrhpz.png) #### 2. 观察者模式角色 - Subject:抽象主题(抽象被观察者),抽象主题角色把所有观察者对象保存在一个集合里,每个主题都可以有任意数量的观察者,抽象主题提供一个接口,可以增加和删除观察者对象。 - ConcreteSubject:具体主题(具体被观察者),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。 - Observer:抽象观察者,是观察者者的抽象类,它定义了一个更新接口,使得在得到主题更改通知时更新自己。 - ConcrereObserver:具体观察者,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。 #### 3. 事件机制实现方式 实现Spring事件机制主要有4个类: 1. ApplicationEvent:事件,每个实现类表示一类事件,可携带数据。 2. ApplicationListener:事件监听器,用于接收事件处理时间。 3. ApplicationEventMulticaster:事件管理者,用于事件监听器的注册和事件的广播。 4. ApplicationEventPublisher:事件发布者,委托ApplicationEventMulticaster完成事件发布。 ##### 3.1 ApplicationEvent ApplicationEvent:应用事件,职责为定义业务 Spring 提供了一个继承于java.util.EventObject 类的ApplicationEvent的的抽象类,并提供了应用上线文事件的抽象实现ApplicationContextEvent 下面的容器关闭、刷新、启动、停止等容器事件 以及RequestHandledEvent(http 请求处理完成事件),可自定义 事件(只需要实现ApplicationEvent 抽象类定义有参构造函数即可,source表示事件源( 我用于事件的回调) ```java public class TestEvent extends ApplicationEvent { private String message; // constructor getter setter } ``` ##### 3.2 ApplicationListener ApplicationListener:事件监听器,职责为处理事件广播器发布的事件。 Spring提供了继承于java.util.EventListener接口的应用监听器接口, ApplicationListener,此接口源码: ```java @FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E event); } ``` 并提供了两个实现:**SmartApplicationListener和GenericApplicationListener接口**。 事件机制监听的方式有两种: 1. 实现ApplicationListener接口 2. EventListener注解形式 代码实例: ```java // 接口方式一 @Component public class AEventListener implements ApplicationListener<TestEvent> { @Override public void onApplicationEvent(TestEvent event) { //逻辑处理 } } // 注解方式二,推荐 @Component public class AEventListener { @EventListener public void listener(TestEvent event) { //逻辑处理 } } ``` ##### 3.3 ApplicationEventMulticaster 事件广播器,职责为将EventPubsher(事件发布者)发布的event 广播给事件EventListener(事件监听器)。 Spring提供了默认的实现SimpleApplicationEventMulticaster,如果用户没有配置自定义事件广播器, 则会默认使用SimpleApplicationEventMulticaster作为事件广播器。在容器刷新的过程中会实例化、初始化事件广播器。 ##### 3.4 ApplicationEventPublisher 事件发布者,职责为发布事件。 spring的ApplicationContext 本来就实现了ApplicationEventPublisher接口,因此应用上下文本来就是 一个事件发布者,在AbstractApplicationContext中实现了事件发布的业务。 如何发布事件呢 ```java // 1. 直接注入ApplicationContext: @Component public class MyEventDoHandle { @Autowired private ApplicationContext applicationContext; public void doSomething(TestEvent obj){ applicationContext.publishEvent(obj); } } // 2. 直接注入ApplicationEventPublisher: 推荐 @Component public class MyEventDoHandle { @Autowired private ApplicationEventPublisher applicationEventPublisher; public void doSomething(TestEvent obj){ applicationEventPublisher.publishEvent(obj); } } ``` #### 4. 代码实例 ##### 4.1 创建事件 ```java public class TestEvent extends ApplicationEvent { private String message; public TestEvent(String message) { // 这里需要回调,就把super传个service实例 super(message); this.message = message; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } } ``` 如定义一个事件,对一个字符型数据处理。 ##### 4.2 创建发布者 ```java @Service public class PublishEvent { @Autowired private ApplicationEventPublisher applicationEventPublisher; public void publish(String message) { applicationEventPublisher.publishEvent(new TestEvent(message)); } } ``` ##### 4.3 创建监听者 ```java @Slf4j @Component public class AEventListener { @EventListener public void listener(TestEvent event) { log.info("监听到数据1:{}", event.getMessage()); } } ``` 调用接口 ```java @RequestMapping("pub") public void pub() { for (int i = 0; i < 5; i++) { publishEvent.publish("你若为我繁华,你好呀:" + (i + 1)); } } ``` 事件监听器默认是同步阻塞的. ##### 4.4 开启异步: 启动类增加此注解,开启异步支持。 ```java @EnableAsync public class Application{ public static void main(String[] args) }{ SpringApplocation.run(Application.class, args); } } ``` 监听方法增加@Async注解,表示该方法为异步方法。高并发时建议指定线程池 ``` @Slf4j @Component public class AEventListener { @Async @EventListener public void listener(TestEvent event) { log.info("监听到数据1:{}", event.getMessage()); } } ``` ##### 4.5 开启事务 ``` // 发布事件的地方加上事务注解 @Service public class PublishEvent { @Autowired private ApplicationEventPublisher applicationEventPublisher; @Transactional public void publish(String message) { applicationEventPublisher.publishEvent(new TestEvent(message)); } } ``` ``` // 将监听处理加入事务 @Log4j2 @Component public class AEventListener { @TransactionalEventListener public void listener(TestEvent event) throws InterruptedException { Thread.sleep(2000); log.info("监听到数据:{}", event.getMessage()); } } ``` [@EventListener注解原理](https://www.huangchaoyu.com/2020/08/08/SpringBoot-%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6,EventListener%E6%B3%A8%E8%A7%A3%E5%8E%9F%E7%90%86/) ##### 4.6 开启泛型 ``` // 事件实现 ResolvableTypeProvider public class BaseEvent<T> extends ApplicationEvent implements ResolvableTypeProvider { private T data; private OperationEnum operation; @Override public ResolvableType getResolvableType() { // 提供运行时返回真正的实例 return ResolvableType.forClassWithGenerics(getClass(), ResolvableType.forClass(getData().getClass())); } } //发送时使用泛型 publisher.publishEvent(new BaseEvent<>(region, INSERT)); //事件监听器,按泛型分开 @EventListener public void onRegionEvent(BaseEvent<Region> event) { log.info("receive event: {}", event); } //用户事件监听器 @EventListener public void onUserEvent(BaseEvent<User> event) { log.info("receive event: {}", event); } ``` ##### 4.7 条件监听 ```java @Log4j2 @Component public class MyEventListener { @Async @EventListener(condition="#event.message=='xxx'") public void listener(TestEvent event) throws InterruptedException { Thread.sleep(2000); log.info("监听到数据:{}", event.getMessage()); } } ``` ———————————————— 原文链接:https://blog.csdn.net/qq_37758497/article/details/118863308 泛型事件:https://www.jianshu.com/p/fd0c358176b9
寒烟濡雨
2024年1月19日 15:39
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
关于 MrDoc
觅思文档MrDoc
是
州的先生
开发并开源的在线文档系统,其适合作为个人和小型团队的云笔记、文档和知识库管理工具。
如果觅思文档给你或你的团队带来了帮助,欢迎对作者进行一些打赏捐助,这将有力支持作者持续投入精力更新和维护觅思文档,感谢你的捐助!
>>>捐助鸣谢列表
微信
支付宝
QQ
PayPal
Markdown文件
分享
链接
类型
密码
更新密码