SpringBootリスナーモードの実装方法

WBOY
リリース: 2023-05-20 19:07:19
転載
982 人が閲覧しました

アプリケーションの起動イベント 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 サイトの他の関連記事を参照してください。

関連ラベル:
ソース:yisu.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート