Spring 中的观察者模式
一、Spring 中观察者模式的四个角色
1. 事件(ApplicationEvent)
ApplicationEvent 是所有事件对象的父类。ApplicationEvent 继承自 jdk 的 EventObject, 所有的事件都需要继承 ApplicationEvent, 并且通过 source 得到事件源。
下列描述了Spring提供的内置事件:
- ContextRefreshedEvent:事件发布在 ApplicationContext 初始化或刷新时(例如:通过在 ConfigurableApplicationContext 接口使用refresh()方法)。这里,“初始化”意味着所有 bean 加载,post-processor bean 被检测到并且激活,单例预先实例化,ApplicationContext 对象可以使用了。只要上下文没有关闭,可以触发多次刷新, ApplicationContext 提供了一种可选择的支持这种“热”刷新。例如:XmlWebApplicationContext 支持热刷新,但 GenericApplicationContext 并非如此。具体是在 AbstractApplicationContext 的 finishRefresh() 方法中。
- ContextStartedEvent:事件发布在 ApplicationContext 开始使用 ConfigurableApplicationContext 接口 start() 方法。这里,“开始”意味着所有生命周期 bean 接收到一个明确的起始信号。通常,这个信号用于明确停止后重新启动,但它也可以用于启动组件没有被配置为自动运行(例如:组件还没有开始初始化)。
- ContextStoppedEvent:事件发布在 ApplicationContext 停止时通过使用 ConfigurableApplicationContext 接口上的 stop() 方法。在这里,“停止”意味着所有生命周期bean接收一个显式的停止信号。停止上下文可以通过重新调用start()方法。
- ContextClosedEvent:事件发布在 ApplicationContext 关闭时通过关闭 ConfigurableApplicationContext 接口()方法。这里,“封闭”意味着所有单例 bean 被摧毁。一个封闭的环境达到生命的终结。它不能刷新或重启。
- RequestHandledEvent:一个特定的web事件告诉所有能处理HTTP请求的bean 。这个事件是在请求完成后发布的。这个事件只适用于使用 Spring 的 DispatcherServlet 的web应用程序。
2. 事件监听(ApplicationListener)
ApplicationListener 事件监听器,也就是观察者。继承自 jdk 的 EventListener,该类中只有一个方法 onApplicationEvent。当监听的事件发生后该方法会被执行。
3. 事件发布(ApplicationContext)
ApplicationContext 是 Spring 中的核心容器,在事件监听中 ApplicationContext 可以作为事件的发布者,也就是事件源。因为 ApplicationContext 继承自 ApplicationEventPublisher。在 ApplicationEventPublisher 中定义了事件发布的方法 — publishEvent(Object event)
4. 事件管理(ApplicationEventMulticaster)
ApplicationEventMulticaster 用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把 Applicationcontext 发布的 Event 广播给它的监听器列表。
二、Spring中实现观察者模式
- 自定义需要发布的事件类,需要继承 ApplicationEvent 类或 PayloadApplicationEvent (该类也仅仅是对 ApplicationEvent 的一层封装)
- 使用 @EventListener 来监听事件或者实现 ApplicationListener 接口。
- 使用 ApplicationEventPublisher 来发布自定义事件(@Autowired注入即可)
@TransactionalEventListener 监听器:如果事件的发布不是在事务(@Transactional)范围内,则监听不到该事件,除非将 fallbackExecution 标志设置为 true:
@TransactionalEventListener(fallbackExecution = true)
如果在事务中,可以选择在事务的哪个阶段来监听事件,默认在事务提交后监听:
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION)
以上介绍的事件监听都是同步,如果需要开启异步支持的话:
@Configuration
@EnableAsync
public class AsyncEventConfiguration implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
return Executors.newCachedThreadPool();
}
}
三、 实战
事件(MyEvent.java)
@Component
public class MyEvent extends ApplicationEvent {
public MyEvent(ApplicationContext source) {
super(source);
System.out.println("MyEvent 构造器执行");
}
public void echo() {
System.out.println("模拟业务逻辑执行");
}
}
事件监听(MyListenerA.java、MyListenerB.java)
@Component
public class MyListenerA implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent myEvent) {
System.out.println("MyListenerA");
myEvent.echo();
}
}
@Component
public class MyListenerB {
@EventListener
public void onApplicationEvent(MyEvent myEvent) {
System.out.println("MyListenerB");
myEvent.echo();
}
}
事件发布(MyPublisher.java)
@Component
public class MyPublisher implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 发布事件
* 监听该事件的监听者都可以获取消息
*
* @param myEvent
*/
public void publisherEvent(MyEvent myEvent) {
System.out.println("---开始发布 myEvent 事件---");
applicationContext.publishEvent(myEvent);
}
}
单元测试(ApplicationTests.java)
@RunWith(SpringRunner.class)
@SpringBootTest
public class ApplicationTests {
@Autowired
private MyPublisher myPublisher;
@Autowired
private MyEvent myEvent;
@Test
public void contextLoads() {
myPublisher.publisherEvent(myEvent);
}
}
演示源代码 :https://github.com/JMCuixy/design-patterns/tree/master/src/main/java/com/example/observer/spring
Spring 中的观察者模式的更多相关文章
- spring事件驱动模型--观察者模式在spring中的应用
spring中的事件驱动模型也叫作发布订阅模式,是观察者模式的一个典型的应用,关于观察者模式在之前的博文中总结过,http://www.cnblogs.com/fingerboy/p/5468994. ...
- 三种方式实现观察者模式 及 Spring中的事件编程模型
观察者模式可以说是众多设计模式中,最容易理解的设计模式之一了,观察者模式在Spring中也随处可见,面试的时候,面试官可能会问,嘿,你既然读过Spring源码,那你说说Spring中运用的设计模式吧, ...
- 如何使用spring中的Log4jConfigListener--删除
使用spring中的Log4jConfigListener有如如下好处: 1. 动态的改变记录级别和策略,不需要重启Web应用,如<Effective Enterprise Java> ...
- JavaEE开发之Spring中的事件发送与监听以及使用@Profile进行环境切换
本篇博客我们就来聊一下Spring框架中的观察者模式的应用,即事件的发送与监听机制.之前我们已经剖析过观察者模式的具体实现,以及使用Swift3.0自定义过通知机制.所以本篇博客对于事件发送与监听的底 ...
- spring 中的设计模式
https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=2247485205&idx=1&sn=63455d2313776d ...
- Spring中使用的设计模式
目录 Spring使用的设计模式 1.单例模式 2.原型模式 3.模板模式 4.观察者模式 5.工厂模式 简单工厂模式 工厂方法模式 6.适配器模式 7.装饰者模式 8.代理模式 9.策略模式 S ...
- 关于spring中的事件体系
在客户这边上班,平时做开发的时候用到了一个客户自己写的一个开发框架,和spring类似,就是功能少一点,提供了依赖注入,事件体系,任务执行等常用的功能,还提供了一个桥接器,可以把spring中的bea ...
- Tomcat与Spring中的事件机制详解
最近在看tomcat源码,源码中出现了大量事件消息,可以说整个tomcat的启动流程都可以通过事件派发机制串起来,研究透了tomcat的各种事件消息,基本上对tomcat的启动流程也就有了一个整体的认 ...
- Spring中ApplicationContext和beanfactory区别---解析一
BeanFacotry是spring中比较原始的Factory.如XMLBeanFactory就是一种典型的BeanFactory.原始的BeanFactory无法支持spring的许多插件,如AOP ...
随机推荐
- React中setState学习总结
react中setState方法到底是异步还是同步,其实这个是分在什么条件下是异步或者同步. 1.先来回顾一下react组件中改变state的几种方式: import React, { Compone ...
- HTTP响应的结构是怎么样的?
HTTP响应由三个部分组成:状态码(Status Code):描述了响应的状态.可以用来检查是否成功的完成了请求.请求失败的情况下,状态码可用来找出失败的原因.如果Servlet没有返回状态码,默认会 ...
- mysql取消严格模式
配置文件my.ini sql-mode="STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION" 修改为 s ...
- Python基础-day02-1
判断(if)语句 目标 开发中的应用场景 if 语句体验 if 语句进阶 综合应用 01. 开发中的应用场景 生活中的判断几乎是无所不在的,我们每天都在做各种各样的选择,如果这样?如果那样?-- 程序 ...
- SpringCloud-创建服务消费者-Feign方式(附代码下载)
场景 SpringCloud-服务注册与实现-Eureka创建服务注册中心(附源码下载): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/deta ...
- JS---最终版本--封装缓动(变速)动画函数---增加任意多个属性&回调函数&层级&透明度
封装缓动(变速)动画函数---增加任意多个属性&回调函数&层级&透明度 相较之前的,增加了2个判断,第一个判断是不是透明度,第二个判断是不是zindex, 都不是,就只是普通属 ...
- iOS开发 - 超级签名实现之描述文件
简介 因为最近企业签掉得太严重了,上头要求实现超级签进行游戏下载.故有了此文章,记录一下过程. 签名原理其实很简单,超级签名的技术就是使用个人开发者账号,将用户的设备当作开发设备进行应用分发.这也导致 ...
- 二维码生成插件qrious
1.qrious是基于canvas的纯JS二维码生成插件 1.1什么是二维码 二维码又称QR Code,QR全称Quick Response,是一个近几年来移动设备上超流行的一种编码方式,它比传统的B ...
- Mysql相关知识总结-持续更新~~~
2019-12-11对varchar类型排序问题的解决 在mysql默认order by 只对数字与日期类型可以排序,但对于varchar字符型类型排序好像没有用了,下面我来给各位同学介绍varcha ...
- Linux-3.14.12内存管理笔记【伙伴管理算法(4)】
此处承接前面未深入分析的页面释放部分,主要详细分析伙伴管理算法中页面释放的实现.页面释放的函数入口是__free_page(),其实则是一个宏定义. 具体实现: [file:/include/linu ...