1、設計模式
基於觀察者模式,主要方法為1 監聽者注冊 2 監聽者注銷 3 執行監聽方法
2、使用篇
類結構圖
MsgEvent:事件對象
MsgListener:事件監聽
MsgListener2:事件監聽(使用注解方式實現)
MsgPublisher:事件發布器
SpringEventTest:單元測試類
測試代碼
MsgEvent
@Data public class MsgEvent extends ApplicationEvent{ //消息ID private String msgId; //消息體 private String payload; public MsgEvent(Object source) { super(source); } }
MsgListener
@Component public class MsgListener implements ApplicationListener<MsgEvent> { @Override public void onApplicationEvent(MsgEvent event) { System.out.println("listenter1 got message, ID:"+event.getMsgId()+", payload:"+event.getPayload()); } }
MsgListener2
@Component public class MsgListener2 { @EventListener public void processMsg(MsgEvent event){ System.out.println("listenter2 got message, ID:"+event.getMsgId()+", payload:"+event.getPayload()); } }
MsgPublisher
@Component public class MsgPublisher implements ApplicationContextAware { //持有當前容器 private ApplicationContext applicationContext; //模擬業務觸發事件 public void publish(){ MsgEvent msgEvent = new MsgEvent("這是一條消息事件"); msgEvent.setMsgId(UUID.randomUUID().toString()); msgEvent.setPayload("事件消息體xxx"); applicationContext.publishEvent(msgEvent); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
SpringEventTest
public class SpringEventTest extends BaseTest{ @Autowired private MsgPublisher msgPublisher; @Test public void publish(){ msgPublisher.publish(); } }
打印結果:
listenter2 got message, ID:5938c2c4-0cda-4abc-b187-9d347102e867, payload:事件消息體xxx
listenter1 got message, ID:5938c2c4-0cda-4abc-b187-9d347102e867, payload:事件消息體xxx
3、源碼分析篇
流程簡述:
1 注冊Listener到容器中,集合存儲 (本文忽略注冊過程源碼,着重發布事件和處理事件代碼)
2 獲取發布器SimpleApplicationEventMulticaster, 發布器在spring啟動時會初始化 initApplicationEventMulticaster()方法 此處不細究
3 發布器根據事件source和事件類class從容器中獲取監聽器集合
4 遍歷監聽器集合, 並調用監聽器EventListener的onApplication方法
類圖展示:
以MsgPublisher為入口 跟蹤方法 applicationContext.publishEvent(msgEvent)
@Component public class MsgPublisher implements ApplicationContextAware { //持有當前容器 private ApplicationContext applicationContext; //模擬業務觸發事件 public void publish(){ MsgEvent msgEvent = new MsgEvent("這是source"); msgEvent.setMsgId(UUID.randomUUID().toString()); msgEvent.setPayload("事件消息體xxx"); applicationContext.publishEvent(msgEvent); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
AbstractApplicationContext 持續追蹤代碼
protected void publishEvent(Object event, ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); if (logger.isTraceEnabled()) { logger.trace("Publishing event in " + getDisplayName() + ": " + event); } // Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; //若繼承自ApplicationEvent 則直接轉Application類型 if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } //非繼承自ApplicationEvent 則標准化成 PayloadApplicationEvent //繼承關系為 PayloadApplicationEvent<T> extends ApplicationEvent 所以最終還是ApplicationEvent方法 else { applicationEvent = new PayloadApplicationEvent<Object>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent)applicationEvent).getResolvableType(); } } // 有可能事件廣播器正在初始化 則存入事件列表延后處理 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); } } } ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException { if (this.applicationEventMulticaster == null) { throw new IllegalStateException("ApplicationEventMulticaster not initialized - " + "call 'refresh' before multicasting events via the context: " + this); } //返回當前容器廣播器 ApplicationEventMulticaster applicationEventMulticaster return this.applicationEventMulticaster; }
SimpleApplicationEventMulticaster 發布器發布事件
//廣播事件
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) { //事件類型 ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); //事件類型篩選容器中已注冊的監聽器 並循環調用 for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @Override public void run() { //調用監聽器 invokeListener(listener, event); } }); } else { //調用監聽器 invokeListener(listener, event); } } }
//篩選獲取監聽器 protected Collection<ApplicationListener<?>> getApplicationListeners( ApplicationEvent event, ResolvableType eventType) { //獲取事件內容 Object source = event.getSource(); //獲取事件source 可以理解為topic Class<?> sourceType = (source != null ? source.getClass() : null); //構建緩存KEY ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType); //Map<ListenerCacheKey , ListenerRetriever> retrieverCache //ListenerRetriever持有事件監聽器集合 按ListenerCacheKey分組 ListenerRetriever retriever = this.retrieverCache.get(cacheKey); //若從緩存中獲取到retriever 則直接返回持有的監聽器集合 if (retriever != null) { return retriever.getApplicationListeners(); } if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { // Fully synchronized building and caching of a ListenerRetriever synchronized (this.retrievalMutex) { retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } retriever = new ListenerRetriever(true); //根據eventType sourceType篩選監聽器 並存入retriever中 Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType, retriever); //放入MAP緩存 this.retrieverCache.put(cacheKey, retriever); return listeners; } } else { // No ListenerRetriever caching -> no synchronization necessary return retrieveApplicationListeners(eventType, sourceType, null); } } //調用監聽器 事件處理 protected void invokeListener(ApplicationListener listener, ApplicationEvent event) { ErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) { try { //執行監聽器的onApplicationEvent方法 listener.onApplicationEvent(event); } catch (Throwable err) { errorHandler.handleError(err); } } else { try { //執行監聽器的onApplicationEvent方法 listener.onApplicationEvent(event); } catch (ClassCastException ex) { String msg = ex.getMessage(); if (msg == null || msg.startsWith(event.getClass().getName())) { // Possibly a lambda-defined listener which we could not resolve the generic event type for Log logger = LogFactory.getLog(getClass()); if (logger.isDebugEnabled()) { logger.debug("Non-matching event type for listener: " + listener, ex); } } else { throw ex; } } } }