concept
In a complete event system, there are the following roles
- Event: describe what happened, such as request processing completed and Spring container refresh completed
- Event source: the generator of an event. Any event must have an event source. For example, the event source of request processing is DispatcherServlet, and the event source of Spring container refresh is ApplicationContext
- Event broadcaster: a bridge between events and event listeners, responsible for notifying events to event listeners
- Event listener: monitors the occurrence of events and can do some processing in the listener
Spring events
Our common event may be ApplicationContextEvent. Its subclass ContextRefreshedEvent is our common event type and is published after Spring instantiates all non deferred loaded bean s.
Let's look at the architecture of Spring events
Spring listener
Event broadcaster
ApplicationContext support for events
ApplicationEventPublisher is an event publisher provided by Spring for users. The real publishing function is entrusted to the above applicationeventmulticast.
Spring provides application event publisher aware, which allows users to obtain the publisher for event publishing.
Mode of use
Spring provides two ways
- Implement the ApplicationListener interface
- Use annotation @ EventListener
Annotation implementation source code
We can directly see EventListenerMethodProcessor. This class implements the smartinitializingsingsingleton interface, which will be called after Spring initializes all non deferred loaded bean s.
public interface SmartInitializingSingleton { /** * Invoked right at the end of the singleton pre-instantiation phase, * with a guarantee that all regular singleton beans have been created * already. {@link ListableBeanFactory#getBeansOfType} calls within * this method won't trigger accidental side effects during bootstrap. * <p><b>NOTE:</b> This callback won't be triggered for singleton beans * lazily initialized on demand after {@link BeanFactory} bootstrap, * and not for any other bean scope either. Carefully use it for beans * with the intended bootstrap semantics only. */ void afterSingletonsInstantiated(); }
In fact, the implementation logic is very simple
for (Method method : annotatedMethods.keySet()) { for (EventListenerFactory factory : factories) { if (factory.supportsMethod(method)) { Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse); if (applicationListener instanceof ApplicationListenerMethodAdapter) { ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator); } context.addApplicationListener(applicationListener); break; } } }
Find out all the methods modified by annotations, create a corresponding ApplicationListener, and call the method after receiving the event.
public void processEvent(ApplicationEvent event) { Object[] args = resolveArguments(event); if (shouldHandle(event, args)) { Object result = doInvoke(args); if (result != null) { handleResult(result); } else { logger.trace("No result object given - no result to handle"); } } }
The sequence of listener calls
We can see in abstractapplicationeventmulticast #retrieveapplicationlisteners that it supports us to specify the order of listeners, and many Spring related orders can be used
- Implement the Ordered interface
- Implement the PriorityOrdered interface
- Using the @ Ordered interface
Asynchronous call listener
By default, the event broadcaster created by Spring calls the notification listener synchronously. We can set or replace the Spring default listener to achieve the purpose of asynchronous call. Of course, it can also be extended. It adopts synchronous or asynchronous methods according to different events, rather than a single or all synchronous or all asynchronous
@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); } } }
Initialize the event propagator before Spring refresh
protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) { this.applicationEventMulticaster = beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class); if (logger.isTraceEnabled()) { logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]"); } } else { this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory); beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster); if (logger.isTraceEnabled()) { logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " + "[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]"); } } }
Replace the original event propagator
@Component("applicationEventMulticaster") public class TestEventMulticaster extends SimpleApplicationEventMulticaster { }