Event-driven model of spring source code analysis series @EventListener

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.

 

9QL95qQ8YUWM0A5THQKJag == .jpg

Make reading source code a pleasure

Long press scan code to follow me

 

Add group discussion

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324981349&siteId=291194637
Recommended