一、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中实现观察者模式

  1. 自定义需要发布的事件类,需要继承 ApplicationEvent 类或 PayloadApplicationEvent (该类也仅仅是对 ApplicationEvent 的一层封装)
  2. 使用 @EventListener 来监听事件或者实现 ApplicationListener 接口。
  3. 使用 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 中的观察者模式的更多相关文章

  1. spring事件驱动模型--观察者模式在spring中的应用

    spring中的事件驱动模型也叫作发布订阅模式,是观察者模式的一个典型的应用,关于观察者模式在之前的博文中总结过,http://www.cnblogs.com/fingerboy/p/5468994. ...

  2. 三种方式实现观察者模式 及 Spring中的事件编程模型

    观察者模式可以说是众多设计模式中,最容易理解的设计模式之一了,观察者模式在Spring中也随处可见,面试的时候,面试官可能会问,嘿,你既然读过Spring源码,那你说说Spring中运用的设计模式吧, ...

  3. 如何使用spring中的Log4jConfigListener--删除

    使用spring中的Log4jConfigListener有如如下好处:    1. 动态的改变记录级别和策略,不需要重启Web应用,如<Effective Enterprise Java> ...

  4. JavaEE开发之Spring中的事件发送与监听以及使用@Profile进行环境切换

    本篇博客我们就来聊一下Spring框架中的观察者模式的应用,即事件的发送与监听机制.之前我们已经剖析过观察者模式的具体实现,以及使用Swift3.0自定义过通知机制.所以本篇博客对于事件发送与监听的底 ...

  5. spring 中的设计模式

    https://mp.weixin.qq.com/s?__biz=MzU0MDEwMjgwNA==&mid=2247485205&idx=1&sn=63455d2313776d ...

  6. Spring中使用的设计模式

    目录 Spring使用的设计模式 1.单例模式 2.原型模式 3.模板模式 4.观察者模式 5.工厂模式 简单工厂模式 工厂方法模式 6.适配器模式 7.装饰者模式 8.代理模式 9.策略模式   S ...

  7. 关于spring中的事件体系

    在客户这边上班,平时做开发的时候用到了一个客户自己写的一个开发框架,和spring类似,就是功能少一点,提供了依赖注入,事件体系,任务执行等常用的功能,还提供了一个桥接器,可以把spring中的bea ...

  8. Tomcat与Spring中的事件机制详解

    最近在看tomcat源码,源码中出现了大量事件消息,可以说整个tomcat的启动流程都可以通过事件派发机制串起来,研究透了tomcat的各种事件消息,基本上对tomcat的启动流程也就有了一个整体的认 ...

  9. Spring中ApplicationContext和beanfactory区别---解析一

    BeanFacotry是spring中比较原始的Factory.如XMLBeanFactory就是一种典型的BeanFactory.原始的BeanFactory无法支持spring的许多插件,如AOP ...

随机推荐

  1. Python 命令行之旅:使用 click 实现 git 命令

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  2. Java Swing JFrame实现全屏--无标题,无边框

    实现方式一: import java.awt.Dimension; import java.awt.Toolkit; import javax.swing.JFrame; public class T ...

  3. 一线大厂Java面试必问的2大类Tomcat调优

    一.前言 最近整理了 Tomcat 调优这块,基本上面试必问,于是就花了点时间去搜集一下 Tomcat 调优都调了些什么,先记录一下调优手段,更多详细的原理和实现以后用到时候再来补充记录,下面就来介绍 ...

  4. WinForm 自定义控件 - RooF

    由3个标签组成 直接代码 public partial class Roof : UserControl { public Roof() { InitializeComponent(); } priv ...

  5. android studio 刚安装需要配置的东西

    智能提示 调整log区域的字体 快捷键中文乱码 自动导入包 意思是创建成员变量的时候,以m开头 下载插件 提高编译的速度

  6. freemarker数据格式化问题(即数值超过三位后自动添加逗号问题)

    实际数据:{value:1007, name:'通用设备'}, 浏览器回显数据: 得出: freemarker 当数据超过3位的时候,会自动用逗号截取 格式如:1,007 解决办法: 加?c,如:${ ...

  7. Git打包指定分支所提交的文件

    原文内容来自于LZ(楼主)的印象笔记,如出现排版异常或图片丢失等问题,可查看当前链接:https://app.yinxiang.com/shard/s17/nl/19391737/da7e233a-c ...

  8. mySql的case when用法

    背景 有点忘了,记录下 写法一 case colume when condition then result when condition then result when condition the ...

  9. 定制Dynamics 365 Portal 界面

    1.通过Portal Designer直接进行定制 以管理员用户登录Portal后会出现Portal Designer,可以进行对homepage的部分元素及Navigation直接进行定制 2.通过 ...

  10. day05生成随机数、do-while循环、for循环、循环流控(break和continue)、循环嵌套

    复习 1.多重if 一个条件触发的情况在3种或以上时 if(<条件1>){ //条件1为真时运行 }else if(<条件2>){ //条件1为假,条件2为真时运行 }else ...