アプリケーションの起動イベント ApplicationStartingEvent を例として説明します。
起動クラスの SpringApplication.run メソッドをエントリ ポイントとして取り、SpringApplication の同じ名前の 2 つのメソッドに従います。メインの run メソッドを見ていきます。このメソッドは比較的長いです。ここでは、リスナーに密接に関連する重要な部分だけを掲載します。
SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting();
開始メソッドをフォローアップします。メソッドの内容は次のとおりです。
void starting() { for (SpringApplicationRunListener listener : this.listeners) { listener.starting(); } }
Here リスナーは getRunListeners メソッドにロードされています。ロードの原則はシステム イニシャライザと同様です。システム イニシャライザのロードについては、SpringBoot のイニシャライザの詳細な分析を参照してください
開始メソッドのロジックは非常に単純で、SpringApplicationRunListener の開始メソッドを呼び出すだけです。この開始メソッドの分析を続けましょう。
EventPublishingRunListener クラス (SpringApplicationRunListener の実装クラス) の開始メソッドを入力します。
@Override public void starting() { this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args)); }
ここでは、新しい ApplicationStartingEvent イベントをブロードキャストするためにブロードキャスターが使用されます。
この multicastEvent メソッドを追跡します:
@Override public void multicastEvent(ApplicationEvent event) { multicastEvent(event, resolveDefaultEventType(event)); }
同じ名前の multicastEvent メソッドを引き続き見ていきます:
@Override 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); } } }
ここの ResolvableType はイベントをラップします。料金は発生しません。スレッド プールを作成していないため、エグゼキュータは空であることに注意してください。
このイベントをリッスンしているすべてのアプリケーション リスナーを取得します
2, invokeListener --> リスナーをアクティブ化します;
getApplicationListeners (AbstractApplicationEventMulticaster クラス (中))
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); // Quick check for existing entry on ConcurrentHashMap... 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)))) { // 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); Collection<ApplicationListener<?>> listeners = retrieveApplicationListeners(eventType, sourceType, retriever); this.retrieverCache.put(cacheKey, retriever); return listeners; } } else { // No ListenerRetriever caching -> no synchronization necessary return retrieveApplicationListeners(eventType, sourceType, null); } }
入力パラメータのイベントは ApplicationStartingEvent で、sourceType は org.springframework.boot.SpringApplication クラスです。私はListenerRetriever型をリスナーを格納するコンテナと考えています。
プログラムはまずキャッシュ内で ListenerRetriever 型の取得者を探し、見つからない場合はロックしてキャッシュから再度検索することがわかります。ここのキャッシュにはコンテンツがないため、返されません。
次に、retrieveApplicationListeners メソッドを使用してリスナーを走査します。 retrieveApplicationListeners メソッドは比較的長いです。ここでは、supportsEvent(listener,eventType,sourceType) メソッドに焦点を当てます。このメソッドは、このリスナーがイベントに注意を払うかどうかを判断するために使用されます。このプロセスには主に、この型が GenericApplicationListener 型であるかどうかの判断が含まれます。プロキシの目的は、リスナーが関心のあるイベントを汎用解析を通じて最終的に取得することです。
リスナーがイベントに興味があると判断された場合、リスナーはリスナー リストに追加されます。
protected boolean supportsEvent( ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) { GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ? (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener)); return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType)); }
イベントのすべてのリスナーが収集されると、multicastEvent (SimpleApplicationEventMulticaster クラス) メソッドがイベントを伝播します。つまり、リスナーの一般的なトリガー インターフェイス メソッドを呼び出します:listener.onApplicationEvent(event); このようにして、このイベントの伝播は完了します。
以上がSpringBootリスナーモードの実装方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。