事件驅動模型也就是咱們常說的觀察者,或者發佈-訂閱模型;理解它的幾個關鍵點:java
好比說訂單狀態變化的時候,可以通知到郵件服務,短信服務,積分變化等等; 若是你是個新手,想象一下你去實現這個業務的代碼怎麼去實現?確定是一個OrderService裏面引入積分Service,短信Service,郵件Service,還有不少不少Service,可能還要調用第三方接口。是否是發現問題所在了,Service耦合嚴重,又是還會出現循環引用的問題,代碼超長,以致於不方便維護。spring
從如上例子能夠看出,應該使用一個觀察者來解耦這些Service之間的依賴關係,如圖:
設計模式
圖中增長了一個Listener來解耦OrderService和其餘Service,即註冊成功後,只須要通知相關的監聽器,不須要關心它們如何處理,處理起來很是容易。這就是一個典型的事件處理模型-觀察者模式,解耦目標對象和它的依賴對象,目標只須要通知它的依賴對象,具體怎麼處理,依賴對象本身決定。好比是異步仍是同步,延遲仍是非延遲等。
其實上邊其實也使用了DIP(依賴倒置原則),依賴於抽象,而不是具體。
仍是就是使用了IOC思想,即之前主動去建立它依賴的Service,如今只是被動等待別人註冊進來。
主要目的是:鬆散耦合對象間的一對多的依賴關係。併發
設計模式裏面的觀察者模式app
JDK觀察者模式異步
JavaBean事件驅動ide
spring事件驅動測試
......ui
JavaBean規範提供了一種監聽屬性變化的事件驅動模型,提供操做JavaBean屬性的類PropertyChangeSupport,PropertyEditorSupport以及PropertyChangeListener支持,PropertyEditorSupport就是目標,而PropertyChangeListener就是監聽器。this
Spring提供的事件驅動模型/觀察者抽象:首先看一下Spring提供的事件驅動模型體系圖,
具體表明者是ApplicationEvent:
一、其繼承自JDK的EventObject,JDK要求全部事件將繼承它,並經過source獲得事件源,好比咱們的AWT事件體系也是繼承自它;
二、系統默認提供了以下ApplicationEvent事件實現:
只有一個ApplicationContextEvent,表示Spring容器事件,且其又有以下實現:
注:org.springframework.context.support.AbstractApplicationContext抽象類實現了LifeCycle的start和stop回調併發布ContextStartedEvent和ContextStoppedEvent事件。
具體表明者是:ApplicationEventPublisher及ApplicationEventMulticaster,系統默認提供了以下實現:
一、ApplicationContext接口繼承了ApplicationEventPublisher,並在AbstractApplicationContext實現了具體代碼,實際執行是委託給ApplicationEventMulticaster(能夠認爲是多播):
protected void publishEvent(Object event, @Nullable ResolvableType eventType) { //省略部分代碼 if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent)event; } else { applicationEvent = new PayloadApplicationEvent(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType(); } } if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { this.getApplicationEventMulticaster().multicastEvent((ApplicationEvent)applicationEvent, eventType); } if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext)this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }
咱們經常使用的ApplicationContext都繼承自AbstractApplicationContext,如ClassPathXmlApplicationContext、XmlWebApplicationContext等,因此自動擁有這個功能。
二、ApplicationContext自動到本地容器裏找一個名字爲」applicationEventMulticaster「的ApplicationEventMulticaster實現,若是沒有本身new一個SimpleApplicationEventMulticaster,代碼以下:
protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = this.getBeanFactory(); if (beanFactory.containsLocalBean("applicationEventMulticaster")) { this.applicationEventMulticaster = (ApplicationEventMulticaster)beanFactory.getBean("applicationEventMulticaster", ApplicationEventMulticaster.class); if (this.logger.isDebugEnabled()) { this.logger.debug("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton("applicationEventMulticaster", this.applicationEventMulticaster); if (this.logger.isDebugEnabled()) { this.logger.debug("Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [" + this.applicationEventMulticaster + "]"); } } }
其中SimpleApplicationEventMulticaster發佈事件的代碼以下:
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event); Iterator var4 = this.getApplicationListeners(event, type).iterator(); while(var4.hasNext()) { ApplicationListener<?> listener = (ApplicationListener)var4.next(); Executor executor = this.getTaskExecutor(); if (executor != null) { executor.execute(() -> { this.invokeListener(listener, event); }); } else { this.invokeListener(listener, event); } } }
能夠看到若是給它一個executor(java.util.concurrent.Executor),它就能夠異步支持發佈事件了,不然就是同步發送。因此咱們發送事件只須要經過ApplicationContext.publishEvent便可,不必再建立本身的實現了。除非有必要。
具體表明者是:ApplicationListener。其繼承自JDK的EventListener,JDK要求全部監聽器將繼承它。
@FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { void onApplicationEvent(E var1); }
它只提供了onApplicationEvent方法,咱們須要在該方法實現內部判斷事件類型來處理,或者指定某一個事件類型(泛型,實現ApplicationListener),並無提供按順序觸發監聽器的語義,因此Spring提供了另外一個接口SmartApplicationListener:
public interface Ordered { int getOrder(); } public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered { boolean supportsEventType(Class<? extends ApplicationEvent> var1); boolean supportsSourceType(@Nullable Class<?> var1); }
該接口支持判斷的事件類型、目標類型,及執行順序。
另外,google guava事件機制使用介紹見文章:使用事件驅動進行代碼解耦-Guava篇
本示例模擬訂單生成與更新時會發送短信與站內信簡單業務場景demo
1. 自定義一些接口以及POJO
/** * 業務事件發佈者 * @author dongsilin * @version 1.0 * @date 2019/1/24 */ public interface BizEventPublisher { /** * 發佈同步事件 * @param eventData */ void publishEvent(Object eventData); /** * 發佈異步事件 * @param eventData */ void publishEventAsync(Object eventData); } /** * 業務事件發佈者 * @author dongsilin * @version 1.0 * @date 2019/1/24 */ public interface BizEventPublisher { /** * 發佈同步事件 * @param eventData */ void publishEvent(Object eventData); /** * 發佈異步事件 * @param eventData */ void publishEventAsync(Object eventData); } /** * 業務事件類型 * @author dongsilin * @version 1.0 * @date 2019/1/24 */ public enum BizEventType { ORDER_CREATE("訂單-建立"), ORDER_UPDATE("訂單-修改"), ; String describe; BizEventType(String describe) { this.describe = describe; } } /** * @author dongsilin * @version 1.0 * @date 2019/1/24 * 測試訂單類 */ @Data public class Order { private long orderId; private long userId; public Order(long orderId, long userId) { this.setOrderId(orderId); this.setUserId(userId); } }
2. 自定義業務事件,包含事件通用數據屬性
/** * @author dongsilin * @version 1.0 * @date 2019/1/24 * 自定義應用業務事件 * @param <S> */ @Data public class BizEvent<S> extends ApplicationEvent implements EventExecutor<S> { private BizEventType eventType; private S data; private BizEvent(BizEventType eventType, S data) { super(eventType); this.eventType = eventType; this.data = data; } public static<S> BizEvent of(BizEventType eventType, S data) { return new BizEvent(eventType, data); } @Override public void executeEvent(Consumer<S> executor) { executor.accept(data); } }
3. 業務事件發佈配置管理
/** * @author dongsilin * @version 1.0 * @date 2019/1/24 * 業務事件發佈配置管理 */ @Slf4j @Component public class BizEventPublisherConfiguration implements BizEventPublisher{ /** 注入事件發佈管理器,用於發佈自定義業務事件 */ @Autowired private ApplicationEventPublisher eventPublisher; /** 異步事件執行線程池 */ private ExecutorService executor = new ThreadPoolExecutor( Runtime.getRuntime().availableProcessors(), Runtime.getRuntime().availableProcessors() * 2, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new ThreadFactoryBuilder().setNameFormat("spring-event-executor-pool-%d").build() ); @Override public void publishEvent(Object eventData) { eventPublisher.publishEvent(eventData); } @Override public void publishEventAsync(Object eventData) { executor.submit(() -> eventPublisher.publishEvent(eventData)); } }
4. 業務事件監聽配置管理
/** * @author dongsilin * @version 1.0 * @date 2019/1/24 * 業務事件監聽配置管理 */ @Slf4j @Component public class BizEventListenerConfiguration implements ApplicationListener<BizEvent> { @Autowired private TestMsgService msgService; /** * 收到事件執行 * @param bizEvent */ @Override public void onApplicationEvent(BizEvent bizEvent) { switch (bizEvent.getEventType()) { // 訂單建立,發送短信,....... case ORDER_CREATE: bizEvent.executeEvent((data) -> { msgService.sendPhoneMsg((Order) data); });break; // 訂單修改,站內信提醒,....... case ORDER_UPDATE: bizEvent.executeEvent((data) -> { msgService.sendWebMsg((Order) data); });break; default: bizEvent.executeEvent((data) -> { log.info("onApplicationEvent bizEvent.data = {}", data); }); } } }
5. 定義兩個測試service,TestOrderService 和 TestMsgService
/** * @author dongsilin * @version 1.0 * @date 2019/1/24 */ @Slf4j @Service public class TestOrderService { @Autowired private BizEventPublisher bizEventPublisher; public void create(Order order) { ...... log.info("TestOrderService create order = {}", order); bizEventPublisher.publishEvent(BizEvent.of(BizEventType.ORDER_CREATE, order)); } public void update(Order order) { ...... log.info("TestOrderService update order = {}", order); bizEventPublisher.publishEventAsync(BizEvent.of(BizEventType.ORDER_UPDATE, order)); } } /** * @author dongsilin * @version 1.0 * @date 2019/1/24 */ @Slf4j @Service public class TestMsgService { public void sendPhoneMsg(Order order) { ...... log.info("TestMsgService sendPhoneMsg order = {}", order); } public void sendWebMsg(Order order) { ...... log.info("TestMsgService sendWebMsg order = {}", order); } }
此處TestOrderService 中並無強制依賴注入TestMsgService,而是經過發佈事件的方式將事件數據發佈到事件管理中心,由事件管理者來統一管理事件處理方式,解決了各個業務service嚴重耦合的場景,實現軟件開發中的「高內聚-低耦合」原則。
經過如上,大致瞭解了Spring的事件機制,可使用該機制很是簡單的完成事件流程。