Spring event mechanism
concept
In a complete event system, there are the following roles
Event: Describes what happened, such as request processing completed, Spring container refresh completed
Event source: The generator of the event, any event must have an event source. For example, the event source of request processing is completed, and the event source of
DispatcherServlet
Spring container refresh isApplicationContext
Event broadcaster: bridge between events and event listeners, responsible for notifying events to event listeners
Event listener: listen for the occurrence of events, you can do some processing in the listener
Spring events
Our common event may be that ApplicationContextEvent
its subclass ContextRefreshedEvent
is our common event type, published after Spring has instantiated all non-lazy loaded beans.
Let's take a look at the architecture of Spring events
Spring listener
event broadcaster
ApplicationContext support for events
ApplicationEventPublisher This is an event publisher provided by Spring to users. The real implementation of the publishing function is still delegated to the ApplicationEventMulticaster above.
Spring provides ApplicationEventPublisherAware so that users can get this publisher for event publishing.
How to use
Spring provides two ways
Implement the ApplicationListener interface
Use the annotation @EventListener
Annotation implementation source code
We directly see that the EventListenerMethodProcessor class implements the interface SmartInitializingSingleton, which is called after Spring has initialized all non-lazy loaded beans.
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 all the annotated methods, then create a corresponding ApplicationListener respectively, and call the method by reflection 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"); } }}
Sequence of listener calls
We can see in AbstractApplicationEventMulticaster#retrieveApplicationListeners that it supports the order in which we specify listeners, and Spring can use many things that involve order.
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 Spring's default listener to achieve the purpose of asynchronous invocation. Of course, it can also be extended to use synchronous or asynchronous according to different events. way, rather than a single either all synchronous or all asynchronous
@Overridepublic 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); } }}
The event propagator is initialized 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 {}
0 Comments