zoukankan      html  css  js  c++  java
  • Spring中的观察者模式事件监听

          在编码过程中,我们经常会遇到完成一个操作需要多个步骤完成的情况。我们可能会把多个步骤写到一个方法里,假如这个操作需要新增步骤,那么势必要修改已有的方法,这违反了开闭原则。

         我们可以使用spring的事件机制来简单地实现这种功能。Spring的事件机制用到了观察者模式,何谓观察者模式?观察者模式(有时又被称为模型(Model)-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

         假如有一个下订单的操作,我们首先需要创建一个Event继承ApplicationEvent,并实现构造方法

    import org.springframework.context.ApplicationEvent;
    
    public class OrderEvent extends ApplicationEvent {
    
        public OrderEvent(Object source) {
            super(source);
        }
    }

         接下来需要定义一个OrderService,并注入ApplicationContext对象,向spring发布下订单事件OrderEvent,类似如下这样:

    import com.study.designer.event.OrderEvent;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.stereotype.Service;
    
    @Service
    public class OrderService {
    
        @Autowired
        private ApplicationContext applicationContext;
    
    
        public void order() {
            applicationContext.publishEvent(new OrderEvent("orderService"));
        }
    }

          向spring发布了OrderEvent事件之后,需要有对应的Listener来响应这个事件,我们可以定义多个事件来监听这个事件来对应OrderEvent需要的一系列步骤。

    这里定义一个OrderSmsListener来虚拟完成短信事件:

    import com.study.designer.event.OrderEvent;
    
    import org.springframework.context.ApplicationListener;
    import org.springframework.stereotype.Component;
    
    @Component
    public class OrderSmsListener implements ApplicationListener<OrderEvent> {
        @Override
        public void onApplicationEvent(OrderEvent orderEvent) {
            System.out.println("orderSmsListener receive event from " + orderEvent.getSource());
        }
    }

         接下来我们编写测试用例来验证功能,可以看到SMS功能已经正常实现:

    import com.study.designer.service.OrderService;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class DesignerApplicationTests {
    
        @Autowired
        private OrderService orderService;
    
        @Test
        public void contextLoads() {
        }
    
    
        @Test
        public void testOrder() {
            orderService.order();
        }
    
    }

        查看ApplicationContext的publishEvent方法,发现spring会获取所有的Listener并向监听对应事件的Listener广播事件

    /**
         * Publish the given event to all listeners.
         * @param event the event to publish (may be an {@link ApplicationEvent}
         * or a payload object to be turned into a {@link PayloadApplicationEvent})
         * @param eventType the resolved event type, if known
         * @since 4.2
         */
        protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
            Assert.notNull(event, "Event must not be null");
    
            // Decorate event as an ApplicationEvent if necessary
            ApplicationEvent applicationEvent;
            if (event instanceof ApplicationEvent) {
                applicationEvent = (ApplicationEvent) event;
            }
            else {
                applicationEvent = new PayloadApplicationEvent<>(this, event);
                if (eventType == null) {
                    eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType();
                }
            }
    
            // Multicast right now if possible - or lazily once the multicaster is initialized
            if (this.earlyApplicationEvents != null) {
                this.earlyApplicationEvents.add(applicationEvent);
            }
            else {
                getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
            }
    
            // Publish event via parent context as well...
            if (this.parent != null) {
                if (this.parent instanceof AbstractApplicationContext) {
                    ((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
                }
                else {
                    this.parent.publishEvent(event);
                }
            }
        }
  • 相关阅读:
    禅道admin忘记密码
    redis conf 解析
    MySQL 安装
    Centos7上安装docker (抄)
    Linux查看CPU和内存使用情况 抄
    上传图片到阿里云OSS和获取上传图片的外网url的步骤
    docker mysql
    Oracle 11g,exp导出时空表、少表的解决办法
    使用com.aspose.words将word模板转为PDF乱码解决方案
    oracle数据库,检索出某几个字段不唯一的那些数据
  • 原文地址:https://www.cnblogs.com/wkzhao/p/10229283.html
Copyright © 2011-2022 走看看