在 Nacos配置服務原理 文中結束時提到過經過發佈 ApplicationListener 刷新事件完成 Context 中屬性值的更新。那麼本章咱們一塊兒分析 ApplicationListener 原理。在開啓 ApplicationListener 解析以前咱們先看一個傳說中模式----觀察者模式(Observer)。html
觀察者模式定義:對象間一種一對多的依賴關係,當一個被觀察的對象改變狀態,則會自動通知它的依賴對象。觀察者模式屬於行爲型模式。這是比較概念性的定義,下面我用一種接近生活的例子來詮釋觀察者模式。上大學的時候,不少學生常常曠課,可是快到期末考試那兩三節課基本是全到的,爲何呢?不錯,老師會劃考試重點!!!這時老師就是被學生觀察的對象,學生就是觀察者。當老師說如下這個知識點考試會考時,下面刷刷刷響起來,同窗們都在用筆畫標記!固然不一樣的學生用的辦法不同,好比學霸會用五光十色的表把重中之重區分出來,學渣可能就無論全用2B鉛筆畫(我就是這學渣中的其一)。看一下老師和學生的關係圖:java
鄭重聲明一下,本學渣比較懶,沒有本身實現一個觀察者模式,直接用的是jdk提供的Observer和Obervable。接下來直接用代碼說明一切。緩存
/** * 被觀察對象 * @author Greiz */ public class TeacherObservable extends Observable { private String examKeyPoints; public String getExamKeyPoints() { return examKeyPoints; } public void setExamKeyPoints(String examKeyPoints) { this.examKeyPoints = examKeyPoints; // 修改狀態 super.setChanged(); // 通知全部觀察者 super.notifyObservers(examKeyPoints); } }
被觀察對象(老師),繼承了Observable。當變量考試重點(examKeyPoints)變了通知觀察者app
public class Observable { private boolean changed = false; private Vector<Observer> obs; public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } public void notifyObservers() { notifyObservers(null); } public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } protected synchronized void setChanged() { changed = true; } }
JDK中的Observable類。成員變量維護一個觀察者的列表,通知的時候遍歷該列表逐個調用update()方法。哈哈,是否是很簡單。分佈式
public interface Observer { void update(Observable o, Object arg); }
監聽者用的也是JDK的,這傢伙比我還懶,就一個方法的接口,要乾的活都交給後代處理。ide
/** * @author Greiz */ public class ExcellentStudentObserver implements Observer { public static final String STUDENT = "我學霸"; @Override public void update(Observable o, Object arg) { System.out.println(STUDENT + "用各類顏色的筆劃重點:" + arg.toString()); } }
監聽者 -- 學霸,當TeacherObservable成員變量改變時最終會調該類的update()方法。this
/** * @author Greiz */ public class PoorStudentObserver implements Observer { public static final String STUDENT = "我學渣一枚"; @Override public void update(Observable o, Object arg) { System.out.println(STUDENT + "用2B鉛筆劃重點:" + arg.toString()); } }
監聽者 -- 學渣(我),當TeacherObservable成員變量改變時最終會調該類的update()方法。spa
老師和學生都有了,剩下的就差把他們聯繫起來了,總不能隨手一把抓吧,專業不對口劃重點也沒有啊!debug
/** * @author Greiz */ public class ObserverManager { public static void main(String[] args) { TeacherObservable observable = new TeacherObservable(); // 給被觀察者對象添加觀察者 observable.addObserver(new PoorStudentObserver()); observable.addObserver(new ExcellentStudentObserver()); // 修改被觀察者 observable.setExamKeyPoints("這是考試重點!!!"); } }
一個簡單的觀察者模式完整的列子完成了。3d
優勢
被觀察對象和觀察者之間解耦。
創建回調機制模型。
缺點
ApplicationListener 跟上面觀察者模式有什麼關係呢?咱們先看源碼,後面一塊兒分析一下他們的關係。這節分兩個階段,一個調用階段,另外一個組裝階段。
下面我畫出調用過程一些重要接口調用時序圖。
源碼解析調用階段都是圍繞這個圖步驟進行。
public class GreizEvent extends ApplicationEvent { public GreizEvent(Object source) { super(source); } private String name = "Greiz"; public String getName() { return name; } public void setName(String name) { this.name = name; } }
自定義事件,須要繼承 ApplicationEvent。
@Component public class GreizListener implements ApplicationListener<GreizEvent> { @Override public void onApplicationEvent(GreizEvent event) { System.out.println("=============" + event.getName()); } }
添加自定義事件監聽者,必須加入Spring容器管理相關注解如 @Component,不然不起做用。
public static void main(String[] args) { ApplicationContext context = new AnnotationConfigApplicationContext("com.greiz.demo.listener"); context.publishEvent(new GreizEvent("Greiz")); }
啓動Spring,發佈自定義事件
接下來進入時序圖中1-6 接口。
protected void publishEvent(Object event, @Nullable ResolvableType eventType) { ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } ... 省略代碼 if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); } ... 省略代碼 }
對應時序圖方法1, AbstractApplicationContext.publishEvent()。publishEvent方法是在 ApplicationEventPublisher 定義的,ApplicationEventPublisher 能夠理解成事件發射器。會調用 getApplicationEventMulticaster()
ApplicationEventMulticaster getApplicationEventMulticaster() throws IllegalStateException { if (this.applicationEventMulticaster == null) { throw new IllegalStateException("ApplicationEventMulticaster not initialized - " + "call 'refresh' before multicasting events via the context: " + this); } return this.applicationEventMulticaster; }
對應時序圖方法2,AbstractApplicationContext.getApplicationEventMulticaster()獲取事件廣播者。applicationEventMulticaster 在Spring啓動refresh過程 調用 initApplicationEventMulticaster() 初始化,是 SimpleApplicationEventMulticaster 實例。
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); Executor executor = getTaskExecutor(); for (ApplicationListener<?> listener : getApplicationListeners(event, type)) { if (executor != null) { executor.execute(() -> invokeListener(listener, event)); } else { invokeListener(listener, event); } } }
對應時序圖方法3,SimpleApplicationEventMulticaster.multicastEvent()。根據事件類型,獲取全部對應的監聽者,而後遍歷通知(俗稱廣播)。
protected Collection<ApplicationListener<?>> getApplicationListeners( ApplicationEvent event, ResolvableType eventType) { Object source = event.getSource(); Class<?> sourceType = (source != null ? source.getClass() : null); ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType); ListenerRetriever retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } if (this.beanClassLoader == null || (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) { synchronized (this.retrievalMutex) { retriever = this.retrieverCache.get(cacheKey); if (retriever != null) { return retriever.getApplicationListeners(); } retriever = new ListenerRetriever(true); Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType, retriever); this.retrieverCache.put(cacheKey, retriever); return listeners; } } else { return retrieveApplicationListeners(eventType, sourceType, null); } }
對應時序圖方法4,AbstractApplicationEventMulticaster.getApplicationListeners()。根據事件類型,先查詢緩存,若是緩存中沒有調用 retrieveApplicationListeners() 獲取,而後存到緩存中。
private Collection<ApplicationListener<?>> retrieveApplicationListeners( ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) { List<ApplicationListener<?>> allListeners = new ArrayList<>(); Set<ApplicationListener<?>> listeners; Set<String> listenerBeans; synchronized (this.retrievalMutex) { listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners); listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans); } for (ApplicationListener<?> listener : listeners) { if (supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { retriever.applicationListeners.add(listener); } allListeners.add(listener); } } if (!listenerBeans.isEmpty()) { BeanFactory beanFactory = getBeanFactory(); for (String listenerBeanName : listenerBeans) { try { Class<?> listenerType = beanFactory.getType(listenerBeanName); if (listenerType == null || supportsEvent(listenerType, eventType)) { ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class); if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) { if (retriever != null) { if (beanFactory.isSingleton(listenerBeanName)) { retriever.applicationListeners.add(listener); } else { retriever.applicationListenerBeans.add(listenerBeanName); } } allListeners.add(listener); } } } catch (NoSuchBeanDefinitionException ex) { } } } AnnotationAwareOrderComparator.sort(allListeners); if (retriever != null && retriever.applicationListenerBeans.isEmpty()) { retriever.applicationListeners.clear(); retriever.applicationListeners.addAll(allListeners); } return allListeners; }
對應時序圖方法5,AbstractApplicationEventMulticaster.retrieveApplicationListeners()。 全部事件監聽者都在this.defaultRetriever 對象中,該對象的值初始化過程咱們在下一節分析。返回過濾後符合本次事件的監聽者。接下來咱們回到 時序圖方法3 中繼續調用 SimpleApplicationEventMulticaster.invokeListener()。
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { listener.onApplicationEvent(event); } catch (ClassCastException ex) { ... 省略代碼 } }
對應時序圖方法6,SimpleApplicationEventMulticaster.doInvokeListener()。 這裏就是真正調用監聽者的方法。
前面提出 ApplicationListener 跟觀察者模式有什麼關係呢?分析 publishEvent(...) 到 onApplicationEvent(...) 調用,是否是很像前面觀察者模式列子中 setExamKeyPoints() --> notifyObservers() --> update()。這一個階段能夠看做就是觀察者模式中調用階段。接下來咱們繼續分析觀察者和被觀察者對象綁定過程---組裝階段。
照舊,以圖開篇,接下來全靠編!!!
在調用階段時序圖5中得知符合對應事件的監聽者是從 AbstractApplicationEventMulticaster 成員 (ListenerRetriever)defaultRetriever 的 applicationListeners 和 applicationListenerBeans 屬性獲取的。組裝階段就是解析 defaultRetriever 初始化負值過程。
applicationListenerBeans 初始化負值過程:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { ... ... 省略代碼 try { ... ... 省略代碼 // ListenerRetriever applicationListenerBeans 初始化負值過程在這裏面 registerListeners(); // ListenerRetriever applicationListeners 初始化負值過程在這裏面 finishBeanFactoryInitialization(beanFactory); ... ... 省略代碼 } catch (BeansException ex) { ... 省略代碼 } finally { ... 省略代碼 } } }
對應時序圖方法1,AbstractApplicationContext.refresh()。省略了一下與本次目的無關的代碼。看註釋就好,哈哈。
protected void registerListeners() { // 初始化階段getApplicationListeners()返回空列表 for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // 根據bean類型獲取 String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } ... 省略代碼 }
對應時序圖方法2,AbstractApplicationContext.registerListeners()。注意看註釋,看註釋,看註釋!!!此處根據bean類型獲取,反應了前面 「添加自定義事件監聽者,必須加入Spring容器管理相關注解如 @Component,不然不起做用」的說法。
public void addApplicationListenerBean(String listenerBeanName) { synchronized (this.retrievalMutex) { this.defaultRetriever.applicationListenerBeans.add(listenerBeanName); this.retrieverCache.clear(); } }
對應時序圖方法3,AbstractApplicationEventMulticaster.addApplicationListenerBean()。
AbstractApplicationEventMulticaster 成員 (ListenerRetriever)defaultRetriever 的applicationListenerBeans 屬性負值完成。
applicationListeners 初始化負值過程:
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { ... 省略代碼 beanFactory.preInstantiateSingletons(); }
對應時序圖方法4,AbstractApplicationContext.finishBeanFactoryInitialization()。
偷懶一次,跟着這個方法debug下去,最終調用AbstractApplicationContext.addApplicationListener()。
public void addApplicationListener(ApplicationListener<?> listener) { Assert.notNull(listener, "ApplicationListener must not be null"); if (this.applicationEventMulticaster != null) { this.applicationEventMulticaster.addApplicationListener(listener); } this.applicationListeners.add(listener); }
對應時序圖方法14,AbstractApplicationContext.addApplicationListener()。
public void addApplicationListener(ApplicationListener<?> listener) { synchronized (this.retrievalMutex) { Object singletonTarget = AopProxyUtils.getSingletonTarget(listener); if (singletonTarget instanceof ApplicationListener) { this.defaultRetriever.applicationListeners.remove(singletonTarget); } this.defaultRetriever.applicationListeners.add(listener); this.retrieverCache.clear(); } }
對應時序圖方法15,AbstractApplicationEventMulticaster.addApplicationListener()。恩,是否是很熟悉的defaultRetriever。
AbstractApplicationEventMulticaster 成員 (ListenerRetriever)defaultRetriever 的applicationListeners 屬性負值完成。
Spring的事件監聽者模型能夠看做是觀察者模式,但Spring對JDK的觀察者模式作了擴展,根據事件類型廣播給對應的監聽者。其實不少Spring源碼都是介於JDK的基礎上作的擴展,若是把JDK比做生活,那麼Spring就是詩人。好詩都是來自生活而高於生活!