Speaking of the front
This time, we mainly introduce the source code analysis of the instantiation process of the listener.
text
We traced the @EventListener source code and found that the implementation behind it is this class EventListenerMethodProcessor, which will be loaded when the spring application context starts. Let me take a look at this class.
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware { protected final Log logger = LogFactory.getLog(getClass()); @Nullable private ConfigurableApplicationContext applicationContext; private final EventExpressionEvaluator evaluator = new EventExpressionEvaluator(); // Increasing the default concurrency of the map can reduce the number of automatic expansions of the map, which will improve the performance of the program to a certain extent. private final Set<Class<?>> nonAnnotatedClasses = Collections.newSetFromMap(new ConcurrentHashMap<>(64));
This class relies on the spring configuration context object and expression parser object.
Find this class that implements the parent class ApplicationContextAware.setApplicationContext() method to get the spring configuration context object.
Find the implementation of this method, which will be executed after all singleton beans are instantiated
@Override public void afterSingletonsInstantiated() {//Execute this method after all singleton beans are created // Let's start to create ApplicationListener and get the factory collection for creating ApplicationListener List<EventListenerFactory> factories = getEventListenerFactories(); // get the configuration context object ConfigurableApplicationContext context = getApplicationContext(); // get the name of the bean String[] beanNames = context.getBeanNamesForType(Object.class); for (String beanName: beanNames) { if (!ScopedProxyUtils.isScopedTarget(beanName)) { Class<?> type = null; try { // Get the type of the initial target class of the bean type = AutoProxyUtils.determineTargetClass(context.getBeanFactory(), beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); } } if (type != null) { // Whether the superclass or superinterface of the class or interface represented by type is the same as ScopedObject if (ScopedObject.class.isAssignableFrom(type)) { try { Class<?> targetClass = AutoProxyUtils.determineTargetClass( context.getBeanFactory(), ScopedProxyUtils.getTargetBeanName(beanName)); if (targetClass != null) { type = targetClass; } } catch (Throwable ex) { // An invalid scoped proxy arrangement - let's ignore it. if (logger.isDebugEnabled()) { logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex); } } } try { processBean(factories, beanName, type); } catch (Throwable ex) { throw new BeanInitializationException("Failed to process @EventListener " + "annotation on bean with name '" + beanName + "'", ex); } } } } }
Focus on this line of code, the operation of instantiating the listener is here
try { processBean(factories, beanName, type); }
protected void processBean( final List<EventListenerFactory> factories, final String beanName, final Class<?> targetType) { // if the target object is not an annotation type if (!this.nonAnnotatedClasses.contains(targetType)) { Map<Method, EventListener> annotatedMethods = null; try { // Find the method annotated with @EventListener annotatedMethods = MethodIntrospector.selectMethods(targetType, (MethodIntrospector.MetadataLookup<EventListener>) method -> AnnotatedElementUtils.findMergedAnnotation(method, EventListener.class)); } catch (Throwable ex) { // An unresolvable type 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 to get the configuration context object ConfigurableApplicationContext context = getApplicationContext(); for (Method method : annotatedMethods.keySet()) { for (EventListenerFactory factory : factories) { if (factory.supportsMethod(method)) { // get the callable method Method methodToUse = AopUtils.selectInvocableMethod(method, context.getType(beanName)); // Create an applicationListener object, which returns the adapter ApplicationListenerMethodAdapter object of GenericApplicationListener ApplicationListener<?> applicationListener = factory.createApplicationListener(beanName, targetType, methodToUse); if (applicationListener instanceof ApplicationListenerMethodAdapter) { // If the specific type of applicationListenr is ApplicationListenerMethodAdapter, initialize it ((ApplicationListenerMethodAdapter) applicationListener).init(context, this.evaluator); } // If the specific type of applicationListenr is ApplicationListenerMethodTransactionalAdapter, configure this listener into the spring configuration context context.addApplicationListener(applicationListener); break; } } } if (logger.isDebugEnabled()) { logger.debug(annotatedMethods.size() + " @EventListener methods processed on bean '" + beanName + "': " + annotatedMethods); } } } }
Take a look at the implementation behind this line of code
If the specific type of applicationListenr is ApplicationListenerMethodTransactionalAdapter, configure this listener into the spring configuration context. This listener type is a listener that supports transactions, which will be specifically parsed in the spring-tx package source code analysis. context.addApplicationListener(applicationListener);
@Override public void addApplicationListener(ApplicationListener<?> listener) { Assert.notNull(listener, "ApplicationListener must not be null"); if (this.applicationEventMulticaster != null) { // If the event publishing manager is not empty, add this listener to it this.applicationEventMulticaster.addApplicationListener(listener); } else { // Publish the listener to the spring context this.applicationListeners.add(listener); } }
After creating the adapter object of applicationListener, inject it into the event release manager or spring context.
to the end
That's all for this introduction. Next time, I will introduce the source code analysis of an event based on the spring-based event-driven model.
Make reading source code a pleasure
Long press scan code to follow me
Add group discussion