Home > Java > javaTutorial > How to implement SpringBoot listener mode

How to implement SpringBoot listener mode

WBOY
Release: 2023-05-20 19:07:19
forward
1057 people have browsed it

Let’s take the application startup event: ApplicationStartingEvent as an example to illustrate:

Taking the SpringApplication.run method of the startup class as the entry point, and following the two methods of the same name in SpringApplication, we will see the main run method, the method is relatively long, here only the key parts closely related to the listener are posted:

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
Copy after login

We follow up the starting method, the content of the method is as follows:

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

Here The listeners have been loaded in the getRunListeners method. The loading principle is similar to the system initializer. Regarding the loading of the system initializer, you can refer to SpringBoot's in-depth analysis of the initializer

The logic of the starting method is very simple, which is to call the starting method of SpringApplicationRunListener. Let's continue to analyze this starting method:

We enter the starting method of the EventPublishingRunListener class (the implementation class of SpringApplicationRunListener):

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

A broadcaster is used here to broadcast the new ApplicationStartingEvent event.

We follow up this multicastEvent method:

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

Continue to look at the multicastEvent method with the same name:

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

The ResolvableType here wraps the event, we will not pay attention to it; because We did not create a thread pool, so the executor is empty. We focus on two parts:

Get all application listeners listening to this event

2, invokeListener --> Activate the listener;

getApplicationListeners (AbstractApplicationEventMulticaster class (medium) method, the code is as follows:

	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);
		}
	}
Copy after login

The event in the input parameter is ApplicationStartingEvent, and the sourceType is the org.springframework.boot.SpringApplication class. I think of the ListenerRetriever type as a container that stores listeners.

It can be seen that the program first looks for the retriever of the ListenerRetriever type in the cache. If it is not found, it locks and searches again from the cache. There is no content in our cache here, so it will not be returned.

Then use the retrieveApplicationListeners method to traverse the listeners. The retrieveApplicationListeners method is relatively long. We focus on the supportsEvent(listener, eventType, sourceType) method. This method is used to determine whether this listener pays attention to the event. The process mainly includes determining whether this type is a GenericApplicationListener type. If not, constructing a The purpose of the proxy is to finally obtain the events that the listener is interested in through generic parsing.

If it is determined that the listener is interested in the event, the listener will be added to the listener list.

	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));
	}
Copy after login

When all listeners for an event are collected, the multicastEvent (SimpleApplicationEventMulticaster class) method will propagate the event. That is, call the general trigger interface method of the listener: listener.onApplicationEvent(event); In this way, the propagation of this event is completed.

The above is the detailed content of How to implement SpringBoot listener mode. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:yisu.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template