zoukankan      html  css  js  c++  java
  • 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中实现观察者模式

    1. 自定义需要发布的事件类,需要继承 ApplicationEvent 类或 PayloadApplicationEvent (该类也仅仅是对 ApplicationEvent 的一层封装)
    2. 使用 @EventListener 来监听事件或者实现 ApplicationListener 接口。
    3. 使用 ApplicationEventPublisher 来发布自定义事件(@Autowired注入即可)

    @TransactionalEventListener 监听器:如果事件的发布不是在事务(@Transactional)范围内,则监听不到该事件,除非将 fallbackExecution 标志设置为 true(@TransactionalEventListener(fallbackExecution = true));如果在事务中,可以选择在事务的哪个阶段来监听事件,默认在事务提交后监听(@TransactionalEventListener(phase = TransactionPhase.AFTER_COMPLETION))。

    以上介绍的事件监听都是同步,如果需要开启异步支持的话:

    1 @Configuration
    2 @EnableAsync
    3 public class AsyncEventConfiguration implements AsyncConfigurer {
    4     @Override
    5     public Executor getAsyncExecutor() {
    6         return Executors.newCachedThreadPool();
    7     }
    8 }

    三、 实战

    事件(MyEvent.java)

     1 @Component
     2 public class MyEvent extends ApplicationEvent {
     3  
     4  
     5     public MyEvent(ApplicationContext source) {
     6         super(source);
     7         System.out.println("MyEvent 构造器执行");
     8     }
     9  
    10     public void echo() {
    11         System.out.println("模拟业务逻辑执行");
    12     }
    13 }

    事件监听(MyListenerA.java、MyListenerB.java)

     1 @Component
     2 public class MyListenerA implements ApplicationListener<MyEvent> {
     3  
     4  
     5     @Override
     6     public void onApplicationEvent(MyEvent myEvent) {
     7         System.out.println("MyListenerA");
     8         myEvent.echo();
     9     }
    10 }
     1 @Component
     2 public class MyListenerB {
     3     
     4     @EventListener
     5     public void onApplicationEvent(MyEvent myEvent) {
     6         System.out.println("MyListenerB");
     7         myEvent.echo();
     8     }
     9     
    10 }

    事件发布(MyPublisher.java)

     1 @Component
     2 public class MyPublisher implements ApplicationContextAware {
     3  
     4     private ApplicationContext applicationContext;
     5  
     6  
     7     @Override
     8     public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
     9         this.applicationContext = applicationContext;
    10     }
    11  
    12     /**
    13      * 发布事件
    14      * 监听该事件的监听者都可以获取消息
    15      *
    16      * @param myEvent
    17      */
    18     public void publisherEvent(MyEvent myEvent) {
    19         System.out.println("---开始发布 myEvent 事件---");
    20         applicationContext.publishEvent(myEvent);
    21     }
    22 }

    单元测试

     1 @RunWith(SpringRunner.class)
     2 @SpringBootTest
     3 public class DesignPatternsApplicationTests {
     4  
     5     @Autowired
     6     private MyPublisher myPublisher;
     7     @Autowired
     8     private MyEvent myEvent;
     9  
    10     @Test
    11     public void contextLoads() {
    12         myPublisher.publisherEvent(myEvent);
    13     }
    14 }

    演示源代码 :https://github.com/JMCuixy/design-patterns/tree/master/src/main/java/com/example/observer/spring

    转载于:https://www.cnblogs.com/jmcui/p/11054756.html

  • 相关阅读:
    调试技巧--Windows端口号是否被占用
    如何制定自己的职业规划
    SQL总结(四)编辑类
    SQL总结(三)其他查询
    CompareAndSwap原子操作原理
    JVM调优之服务内存超过阈值报警
    Javassist中文技术文档
    微言Netty:分布式服务框架
    共享变量边界处理
    Netty客户端发送消息并同步获取结果
  • 原文地址:https://www.cnblogs.com/it-deepinmind/p/13265179.html
Copyright © 2011-2022 走看看