This series is divided into five parts


1.
How are @Component, @service, etc annotations parsed
2.@Enableq Driving principle (latest 20200705)

3.@EnableAutoConfiguration Processing logic
4. Spring, springBoot event
5. Write a SpringBootstarter in just four steps

The introduction

The Spring event mechanism has three core parts: events, listening mode, and broadcast. We will introduce them separately below.

The Spring event

Spring’s event API corresponds to ApplicationEvent. It inherits ava.util.EventObject. Shows that the parent class constructor is called to pass the event source.


Public Abstract Class ApplicationEvent extends EventObject {public ApplicationEvent(Object)source) {
		super(source); this.timestamp = System.currentTimeMillis(); } // omit other code}Copy the code


Spring built-in events

The event name annotation
ContextRefreshedEvent Spring application context-ready events
ContextStartedEvent Spring application context launch event
ContextStopedEvent Spring application context stop event
ContextClosedEvent Spring application context closure event
Custom allow generic event, if interested can see: org. Springframework. Context. PayloadApplicationEvent


Spring event listener

Two kinds of monitoring methods

1. Implement ApplicationListener interface or @EventListener, can listen to 1 to a variety of events, support generic events
2. @eventListener Async (@eventListener) : Async (@eventListener);
The difference between synchronous and asynchronous table @eventListener
Method type Access modifier The return type The number of arguments The parameter types note
synchronous public Any type 0 or 1

Listener event class

Type or a subclass thereof

Will return the value

As the direction of events

After the spread

asynchronous public void 0 or 1

Listener event class

Type or a subclass thereof

If something goes wrong, no
Will propagate to tune
The user.
It doesn’t pass back
Broadcast events

@ EventListener principle

To find the entrance


Entrance class EventListenerMethodProcessor is processing @ EventListener annotations
Find the main method
To view
EventListenerMethodProcessor class, brief translation is as follows:

1.将@

The EventListener method is converted to
ApplicationListener sample

2. Implement
BeanFactoryPostProcessor is used for retrieval
EventListenerFactory

Avoid AOP enhancements, EventListenerFactory

In the view, EventListenerMethodProcessor class diagram

ApplicationContextAware is used to inject ApplicationContext.
The BeanFactoryPostProcessor is used to get the EventListenerFactory from the class annotations.
Here the need to pay attention to should be SmartInitializingSingleton# afterSingletonsInstantiated method.
See the comments for this method
Public interface SmartInitializingSingleton {/ * * * instantiation completed calls, ensure that all normal singleton Bean is created call ListableBeanFactory *#getBeansOfType has no side effects* Note: * This callback is not triggered for lazy-loaded singleton beans. * And other scoped beans will not trigger this callback. * Use with caution and should only be used for boot functions. */ void afterSingletonsInstantiated(); }Copy the code


AfterSingletonsInstantiated can be seen from the method annotation, this method can be used to guide function.
View the source EventListenerMethodProcessor
The logic is to find the BeanName and Bean corresponding Type, the specific logic delegate toProcessBean, below is the source code for processBean
Public class EventListenerMethodProcessor {/ / the other omitted private void processBean (final String beanName, final class <? > targetType) {if(! this.nonAnnotatedClasses.contains(targetType) && ! targetType.getName().startsWith("java") &&! isSpringContainerClass(targetType)) { Map<Method, EventListener> annotatedMethods = null; Try {/ / find out all the EventListener annotation methods annotatedMethods = MethodIntrospector. SelectMethods (targetType, (MethodIntrospector.MetadataLookup<EventListener>) method -> AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class)); } catch (Throwable ex) { // An unresolvabletype in a method signature, probably from a lazy bean - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve methods for bean with name '" + beanName + "'", ex); } } if (CollectionUtils.isEmpty(annotatedMethods)) { this.nonAnnotatedClasses.add(targetType); if (logger.isTraceEnabled()) { logger.trace("No @EventListener annotations found on bean class: " + targetType.getName()); } } else { // Non-empty set of methods ConfigurableApplicationContext context = this.applicationContext; Assert.state(context ! = null, "No ApplicationContext set"); List
         
           factories = this.eventListenerFactories; Assert.state(factories ! = null, "EventListenerFactory List not initialized"); for (Method method : annotatedMethods.keySet()) { for (EventListenerFactory factory : factories) { if (factory.supportsMethod(method)) { Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); / / by converting EventListenerFactory ApplicationListenerMethodAdapter ApplicationListener 
           applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse); if (applicationListener instanceof ApplicationListenerMethodAdapter) { ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator); } // Register the event listener in the application context. context.addApplicationListener(applicationListener); break; } } } if (logger.isDebugEnabled()) { logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '
         " + beanName + "': " + annotatedMethods); } } } } }Copy the code


AopUtils. SelectInvocableMethod are not allowed to access a private method, static method, agent method, is proved
@EventListenerMust be decorated with public
Summary of logic
1. The logic of this method is to add the @eventListener method
2. By

EventListenerFactory into

ApplicationListenerMethodAdapter,

3. The event listener is registered in the live text.


@ EventListener summary

EventListenerMethodProcessor is @ the EventListener life cycle of the processor, implements the interface SmartInitializingSingleton afterSingletonsInstantiated method, A:
  • The logic of this method is to take the method at @EventListener,
  • through
    EventListenerFactory into

    ApplicationListenerMethodAdapter,

  • The event listener is registered in the live context.
2. DefaultEventListenerFactory is @ EventListener method and ApplicationListener adapter factory
3. ApplicationListenerMethodAdapter adapter classes.

Spring’s broadcaster

Radio apparatus for ApplicationEventMulticaster, its default implementation for SimpleApplicationEventMulticaster
It has two main responsibilities, maintaining the ApplicationListener association. This one is easier, but let’s focus on broadcast messages.
@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 the code


Call getApplicationListeners and traverse onApplicationEvent.
In his father’s class AbstractApplicationEventMulticaster view getApplicationListeners method.
protected Collection<ApplicationListener<? >> getApplicationListeners( ApplicationEvent event, ResolvableType eventType) { Objectsource= 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);
         returnlisteners; }}else {
      // No ListenerRetriever caching -> no synchronization necessary
      return retrieveApplicationListeners(eventType, sourceType, null); }}Copy the code


Internal maintenance of a final Map retrieverCache Maintains the event type and data source type ,>
ListenerCacheKey is eventType (corresponding to the generic or event class itself) and sourceType (source in the ApplicationEvent constructor), (corresponding to ApplicationEvent).

SimpleApplicationEventMulticaster summary:

1. SimpleApplicationEventMulticaster have two role, associated ApplicationListener, broadcasting ApplicationEvent.
2. SimpleApplicationEventMulticaster internal maintain a final Map < ListenerCacheKey ListenerRetriever > retrieverCache maintenance event type and the type of data source
3. ListenerCacheKey is eventType (corresponding to the generic or event class itself) and sourceType (source in the ApplicationEvent constructor)
4. ListenerRetriever is AbstractApplicationEventMulticaster inner classes, corresponding ApplicationListener collection
5. ApplicationEventMulticaster broadcast events, multicastEvent (ApplicationEvent) and multicastEvent (ApplicationEvent ResolvableType)
Internal calls to getApplicationListeners, traverses onApplicationEvent


Supplementary notes:
Through the ApplicationEventPublisher ApplicationEventPublisherAware, what is?
Solve this, you need to look at ApplicationContextAwareProcessor# postProcessBeforeInitialization
Internally, the invokeAwareInterfaces method is invoked to handle the injection logic for the various Aware interfaces.
private void invokeAwareInterfaces(Object bean) {
   if(bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());  }if (bean instanceof EmbeddedValueResolverAware) {
      ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
   }
   if (bean instanceof ResourceLoaderAware) {
      ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
   }
   if (bean instanceof ApplicationEventPublisherAware) {
      ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
   }
   if (bean instanceof MessageSourceAware) {
      ((MessageSourceAware) bean).setMessageSource(this.applicationContext);
   }
   if(bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }}Copy the code


So here’s the answer. ApplicationEventPublisherAware ApplicationEventPublisher instance is gained by the current ApplicationContext.


This section describes Spring Boot events

Springboot event

SpringBoot events inherit from and are subclasses of ApplicationEvent
SpringBoot event source is SpringApplication, according to the internal events EventPublishingRunListener lifecycle callback methods in turn.
1.5 a ApplicationStartingEvent
ApplicationEnvironmentPreparedEvent
ApplicationPreparedEvent
ApplicationStartedEvent
ApplicationReadyEvent, spring application context released later
ApplicationFailedEvent, released after the Spring application context

Spring Boot event listener

The SpringApplication association ApplicationListener for the SpringApplication association
Under class-path, the ApplicationListener object collection in the meta-INF/Spring. factories resource
2.SpringApplication#addListeners(…) Or SpringApplicationBuilder# listeners (…). According to the assembly

Spring Boot broadcaster

After 2.0 SimpleApplicationEventMulticaster, is a specific, not Shared with spring framework.