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