Spring 中的观察者模式

摘要:
ApplicationEvent继承自jdk的EventObject,所有的事件都需要继承ApplicationEvent,并且通过source得到事件源。只要上下文没有关闭,可以触发多次刷新,ApplicationContext提供了一种可选择的支持这种“热”刷新。ContextStoppedEvent:事件发布在ApplicationContext停止时通过使用ConfigurableApplicationContext接口上的stop()方法。这个事件只适用于使用Spring的DispatcherServlet的web应用程序。

一、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 中的观察者模式》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇EasyUI常用组件(基础)Asp.net core 学习笔记之 authen + autho + oidc + oauth + spa 第八篇 OAuth &amp;amp; OpenID Connect (OIDC)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

JavaWeb总结(八)

对象作用域    在Servlet里可以用一个名字绑定一个对象,并且在应用中传递和使用这个对象 作用域对象 属性操作方法 作用域范围说明 ServletContext(上下文) void setAttribute(String,Object) Object getAttribute(Sting) void removeAttribute(Str...

XD 05

项目启动方式 1. 在 springBoot application 上右键 run as Java application 2. run as mvn install 会打包一个jar 包 3. war 在 tomcat, war 包方式, 一般 springBoot 都是使用 jar 包启动了 a. 首先在 pom 文件中添加 <packagin...

Javaweb统计在线人数的小栗子

最近在学习Javaweb相关的内容(不黑不吹之前对web开发零基础),下面通过一个统计在线人数的小栗子讲讲Servlet监听器吧 开发环境 eclipse  tomcat 7 先说说这个小栗子的构思:         首先要考虑的就是通过什么方式能够统计在线人数?很容易想到可以通过session来统计在线人数为什么不是request呢?因为request在...

Android监听

流程模型图: 文字表述: 事件监听机制中由事件源,事件,事件监听器三类对象组成 处理流程如下: Step 1:为某个事件源(组件)设置一个监听器,用于监听用户操作 Step 2:用户的操作,触发了事件源的监听器 Step 3:生成了对应的事件对象 Step 4:将这个事件源对象作为参数传给事件监听器 step 5:事件监听器对事件对象进行判断,执行对应的...

java事件

JAVA事件机制 事件机制包含3个部分:事件,监听器,事件源 1.事件 继承java.util.EventObject类,封装了事件源对象及跟踪事件相关信息 自定义事件类CustomEvent import java.util.EventObject; public class CustomEvent extends EventObject {...

深入理解Apollo核心机制之配置读取——ConfigService定时扫描

概述 之前我们了解了,客户端会每秒(默认)长轮询Config Service,等待通知,然后去主动拉取配置文件。本文主要跟进Config Service主动轮询ReleaseMessage表,并通知对应监听器的源码,最终终止客户端长轮询的源码。附上之前的链接《深入理解Apollo核心机制之配置读取——前言》 监听器介绍 Config Service中有一些...