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)
    

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

    @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

  • 相关阅读:
    Chrome cookies folder
    Fat URLs Client Identification
    User Login Client Identification
    Client IP Address Client Identification
    HTTP Headers Client Identification
    The Personal Touch Client Identification 个性化接触 客户识别
    购物车 cookie session
    购物车删除商品,总价变化 innerHTML = ''并没有删除节点,内容仍存在
    453
    购物车-删除单行商品-HTMLTableElement.deleteRow()
  • 原文地址:https://www.cnblogs.com/jmcui/p/11054756.html
Copyright © 2011-2022 走看看