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);
            }
        }
    }

 

posted @ 2019-01-06 16:26  gluawwa  阅读(1377)  评论(0编辑  收藏  举报