Recently, I read the source code of SpringBoot and found a strange phenomenon: there are two places in the project with the function of publishing events. One is the SpringApplicationRunListener interface; The other is the publishEvent method of the ApplicationEventPublisher interface, which is implemented by the ApplicationContext interface. The standard listener mode should only have one place to publish events. Why are there two here?
Let's start with the conclusion.
After careful analysis, it is found that the SpringApplicationRunListener interface belongs to the SpringBoot package, which is used to publish events of SpringBoot related processes; The ApplicationEventPublisher interface belongs to org springframework. The context package is used for ApplicationContext to be invoked in the refresh process, and refresh is the core method of application context initiation.
In other words, the SpringApplicationRunListener interface is used to listen to the startup process of Spring boot, and ApplicationEventPublisher is used to listen to the startup process of Spring application context.
So why use the new client to listen to the process of SpringBoot?
The reason is that the SpringBoot project is an extension of the Spring project, so the Spring code and the SpringBoot code cannot be coupled. In order to listen to the startup process of SpringBoot itself, the SpringApplicationRunListener interface is introduced. Another reason is that during the SpringBoot startup process, the listener needs to be used, and the ApplicationContext has not been refresh ed, so the publishEvent function of ApplicationContext cannot be used.
The above is why the same simpleapplicationeventmulticast is called in the two places (of course, the simpleapplicationeventmulticast instances called in the two places are different to separate listeners).
1.SpringApplicationRunListener
public interface SpringApplicationRunListener { void starting(); void environmentPrepared(ConfigurableEnvironment environment); void contextPrepared(ConfigurableApplicationContext context); void contextLoaded(ConfigurableApplicationContext context); void finished(ConfigurableApplicationContext context, Throwable exception); }
The only implementation class of this interface is EventPublishingRunListener, which calls simpleapplicationeventmulticast to broadcast events and publish different events in the above five processes started by spring application.
2.AbstractApplicationContext
This class is an abstract class of application context. The publishEvent method in it is related to the listener. No code is pasted here. It calls the attribute applicationeventmulticast of AbstractApplicationContext, which is initialized through the initapplicationeventmulticast method. In fact, it also initializes the instance of simpleapplicationeventmulticast. Let's analyze the broadcaster related classes.
3.SimpleApplicationEventMulticaster
The implementation class inherits from abstractapplicationeventmulticast, and the abstractapplicationeventmulticast abstract class implements the applicationeventmulticast interface.
Abstractapplicationeventmulticast abstract class defines the standard implementation of the broadcaster and defines the internal class of the listener retriever. The listener retriever separates the function of obtaining listeners and can obtain listeners in multiple ways, Here, the listener is obtained through the listener saved by the applicationListeners attribute and the listener beanName saved by the applicationListenerBeans.
private class ListenerRetriever { public final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<ApplicationListener<?>>(); public final Set<String> applicationListenerBeans = new LinkedHashSet<String>(); private final boolean preFiltered; public ListenerRetriever(boolean preFiltered) { this.preFiltered = preFiltered; } public Collection<ApplicationListener<?>> getApplicationListeners() { List<ApplicationListener<?>> allListeners = new ArrayList<ApplicationListener<?>>( this.applicationListeners.size() + this.applicationListenerBeans.size()); allListeners.addAll(this.applicationListeners); if (!this.applicationListenerBeans.isEmpty()) { BeanFactory beanFactory = getBeanFactory(); for (String listenerBeanName : this.applicationListenerBeans) { try { ApplicationListener<?> listener = beanFactory.getBean(listenerBeanName, ApplicationListener.class); if (this.preFiltered || !allListeners.contains(listener)) { allListeners.add(listener); } } catch (NoSuchBeanDefinitionException ex) { // Singleton listener instance (without backing bean definition) disappeared - // probably in the middle of the destruction phase } } } AnnotationAwareOrderComparator.sort(allListeners); return allListeners; } }
SimpleApplicationEventMulticaster extends the function of multi-threaded call listener, but if the setTaskExecutor method is not called externally to set the thread pool, the current thread is still used by default.
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster { private Executor taskExecutor; private ErrorHandler errorHandler; @Override public void multicastEvent(ApplicationEvent event) { multicastEvent(event, resolveDefaultEventType(event)); } @Override public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @Override public void run() { invokeListener(listener, event); } }); } else { invokeListener(listener, event); } } } protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) { ErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) { try { doInvokeListener(listener, event); } catch (Throwable err) { errorHandler.handleError(err); } } else { doInvokeListener(listener, event); } } private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { try { listener.onApplicationEvent(event); } catch (ClassCastException ex) { String msg = ex.getMessage(); if (msg == null || matchesClassCastMessage(msg, event.getClass())) { Log logger = LogFactory.getLog(getClass()); if (logger.isDebugEnabled()) { logger.debug("Non-matching event type for listener: " + listener, ex); } } else { throw ex; } } } }
4. Event and event type
All listeners that implement the ApplicationListener interface can only get the events that implement the ApplicationEvent abstract class. The information saved by the abstract class is only the creation time of the event. In addition, the ApplicationEvent abstract class inherits the ordinary class of EventObject, which is Java Under util package, there is only one source attribute, indicating the source of the event.
Listeners that implement the GenericApplicationListener interface can add whether the corresponding resolvable type is supported
And source type judgment.
ResolvableType can be constructed through ApplicationEvent, and the instance of the corresponding ApplicationEvent is placed in the resolved property of ResolvableType.
private ResolvableType resolveDefaultEventType(ApplicationEvent event) { return ResolvableType.forInstance(event); } public static ResolvableType forInstance(Object instance) { Assert.notNull(instance, "Instance must not be null"); if (instance instanceof ResolvableTypeProvider) { ResolvableType type = ((ResolvableTypeProvider) instance).getResolvableType(); if (type != null) { return type; } } return ResolvableType.forClass(instance.getClass()); } public static ResolvableType forClass(Class<?> clazz) { return new ResolvableType(clazz); } private ResolvableType(Class<?> clazz) { this.resolved = (clazz != null ? clazz : Object.class); this.type = this.resolved; this.typeProvider = null; this.variableResolver = null; this.componentType = null; this.hash = null; }