This series is divided into five parts
1.
How are @Component, @service, etc annotations parsed
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:
EventListenerMethodProcessor class, brief translation is as follows:
1.将@
The EventListener method is converted toApplicationListener sample2. ImplementBeanFactoryPostProcessor is used for retrievalEventListenerFactoryAvoid 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
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
@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.