Event Listening for Spring
ApplicationListener
The ApplicationListener is part of the Spring event mechanism and works with the abstract class ApplicationEvent to complete the event mechanism for the ApplicationContext.
If an ApplicationListener's Bean exists in the container, the corresponding Bean is triggered when the ApplicationContext calls the publishEvent method.This process is the implementation of a typical observer pattern.
Source code:
@FunctionalInterface public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); }
Listening for ContextRefreshedEvent events
Take Spring's built-in event ContextRefreshedEvent for example. When an ApplicationContext is initialized or refreshed, the ContextRefreshedEvent event is triggered. Here we implement an ApplicationListener to listen for this event.
@Component // The class needs to be instantiated as a Bean public class LearnListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { // Number of Bean s in Print Container System.out.println("Listener Gets Initialization in Container Bean Number:" + event.getApplicationContext().getBeanDefinitionCount()); } }
Event Publishing
After the container is created, an event is published in the finishRefresh() method - ContextRefreshedEvent
Let's take a closer look at how this event was published
protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); // Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType(); } } // Multicast right now if possible - or lazily once the multicaster is initialized if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { //Get the dispatcher for the event getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); } // Publish event via parent context as well... if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }
Dispatch event: getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
Executing invokeListener here is primarily an interface method that calls listener back and forth
This is the process of event publishing in spring.
Event Dispatcher
One of the steps in event publishing is to get the event dispatcher. Where was the event dispatcher created?
In fact, when the container is initialized, the initApplicationEventMulticaster() method is executed to initialize the event dispatcher for the container.
protected void initApplicationEventMulticaster() { ConfigurableListableBeanFactory beanFactory = getBeanFactory(); //First determine if there is an applicationEventMulticaster in the container 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 { //Create a dispatcher if not 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() + "]"); } } }
APPLICATION_EVENT_MULTICASTER_BEAN_NAME:
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
Where does the listener come from
The refresh() method executes registerListeners() to register listeners in the container
protected void registerListeners() { // Register statically specified listeners first. for (ApplicationListener<?> listener : getApplicationListeners()) { getApplicationEventMulticaster().addApplicationListener(listener); } // Do not initialize FactoryBeans here: We need to leave all regular beans // uninitialized to let post-processors apply to them! //Get Bean Names for All Listeners by Type String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false); for (String listenerBeanName : listenerBeanNames) { //Add listener to dispatcher getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName); } // Publish early application events now that we finally have a multicaster... Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents; this.earlyApplicationEvents = null; if (earlyEventsToProcess != null) { for (ApplicationEvent earlyEvent : earlyEventsToProcess) { getApplicationEventMulticaster().multicastEvent(earlyEvent); } } }
@EventListener
In addition to implementing the ApplicationListener interface to complete event listening, the @EventListener annotation also listens for events
Simply label @EventListener as a method:
@EventListener(classes = {ApplicationEvent.class}) public void listen(ApplicationEvent applicationEvent){ System.out.println("Monitor:"+applicationEvent); }