Maison  >  Article  >  Java  >  Comment implémenter le mode d'écoute SpringBoot

Comment implémenter le mode d'écoute SpringBoot

WBOY
WBOYavant
2023-05-20 19:07:191001parcourir

Prenons l'événement de démarrage de l'application : ApplicationStartingEvent comme exemple pour illustrer :

Prenons la méthode SpringApplication.run de la classe de démarrage comme point d'entrée Après avoir suivi les deux méthodes du même nom dans SpringApplication, nous verrons l'exécution principale. méthode, qui est relativement longue, seules les parties clés étroitement liées à l'auditeur sont postées ici :

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();

Nous faisons suite à cette méthode de départ, le contenu de la méthode est le suivant :

void starting() {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.starting();
	}
}

Les auditeurs ici ont été chargés. dans la méthode getRunListeners, et le principe de chargement est similaire à celui de l'initialiseur système. Concernant le chargement de l'initialiseur système, vous pouvez vous référer à l'analyse approfondie des initialiseurs de SpringBoot. La logique de la méthode de démarrage est très simple, qui consiste à appeler le démarrage. méthode de SpringApplicationRunListener. Continuons à analyser cette méthode de démarrage :

Nous entrons dans la méthode de démarrage de la classe EventPublishingRunListener (classe d'implémentation de SpringApplicationRunListener) :

	@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
	}

Un diffuseur est utilisé ici pour diffuser le nouvel événement ApplicationStartingEvent.

Nous suivons cette méthode multicastEvent :

	@Override
	public void multicastEvent(ApplicationEvent event) {
		multicastEvent(event, resolveDefaultEventType(event));
	}

Continuons à regarder la méthode multicastEvent du même nom :

	@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);
			}
		}
	}

Le ResolvableType ici enveloppe l'événement, nous n'y prêtons donc pas attention puisque nous n'avons pas créé de ; pool de threads, l’exécuteur est vide. Nous nous concentrons sur deux parties :

Obtenir que tous les auditeurs d'application écoutent cet événement

2. InvoquerListener --> Activer l'écouteur ;

getApplicationListeners (dans la classe AbstractApplicationEventMulticaster), le code est le suivant :

	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);
		}
	}

Entrez le paramètres L'événement dans est ApplicationStartingEvent et le sourceType est la classe org.springframework.boot.SpringApplication. Je considère le type ListenerRetriever comme un conteneur qui stocke les écouteurs.

On voit que le programme recherche d'abord un récupérateur de type ListenerRetriever dans le cache, s'il n'est pas trouvé, il le verrouille et le recherche à nouveau dans le cache. Il n'y a aucun contenu dans notre cache ici, il ne sera donc pas renvoyé.

Utilisez ensuite la méthode retrieveApplicationListeners pour parcourir les écouteurs. La méthode retrieveApplicationListeners est relativement longue.Nous nous concentrons sur la méthode supportsEvent(listener, eventType, sourceType) Cette méthode est utilisée pour déterminer si cet écouteur prête attention à l'événement.Le processus consiste principalement à déterminer si ce type est un type GenericApplicationListener. non, en construisant un proxy. Le but du proxy est d'obtenir finalement les événements qui intéressent l'auditeur grâce à une analyse générique.

S'il est déterminé que l'auditeur est intéressé par l'événement, l'auditeur sera ajouté à la liste des auditeurs.

	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));
	}

Lorsque tous les écouteurs d'un événement sont collectés, la méthode multicastEvent (classe SimpleApplicationEventMulticaster) propagera l'événement. Autrement dit, appelez la méthode d'interface de déclenchement générale de l'écouteur : Listener.onApplicationEvent(event); De cette façon, la propagation de cet événement est terminée.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer