preface

Source code version:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.28..RELEASE</version>
    </dependency>
Copy the code

A look at the spring on how to use ConfigurationClassPostProcessor to parse the configuration file. This basically see AbstractApplicationContext registerBeanPostProcessors method,

                // Register bean processors that intercept bean creation.
            registerBeanPostProcessors(beanFactory);
Copy the code

As you can see from the comments above the method, this method is registered Bean post-processing.

The body of the

The following positioning to PostProcessorRegistrationDelegate registerBeanPostProcessors method directly:

public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {/ / factory in type is a collection of beanName BeanPostProcessor String [] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false); // Register BeanPostProcessorChecker that logs an info message when // a bean is created during BeanPostProcessor instantiation, i.e. when // a bean is not eligible for getting processed by all BeanPostProcessors. int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length; beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount)); // Separate between BeanPostProcessors that implement PriorityOrdered, // Ordered, // Implement PriorityOrdered, Ordered BeanPostProcessors and the rest. Is actually the BeanPostProcessors classification List < BeanPostProcessor > priorityOrderedPostProcessors = new ArrayList < > (); List<BeanPostProcessor> internalPostProcessors = new ArrayList<>(); List<String> orderedPostProcessorNames = new ArrayList<>(); List<String> nonOrderedPostProcessorNames = new ArrayList<>(); for (String ppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = BeanPostProcessor.class); priorityOrderedPostProcessors.add(pp); If (pp instanceof MergedBeanDefinitionPostProcessor) {/ / separation to achieve MergedBeanDefinitionPostProcessor again internalPostProcessors.add(pp); }} else if (the beanFactory isTypeMatch (ppName, Ordered. Class)) {/ / separation of Ordered orderedPostProcessorNames. Add (ppName); } else {/ / the rest, the rest of the nonOrderedPostProcessorNames. Add (ppName); }} // First, register the BeanPostProcessors that implement PriorityOrdered. Registration for PriorityOrdered BeanPostProcessors sortPostProcessors (priorityOrderedPostProcessors, the beanFactory); / / sorting registerBeanPostProcessors (the beanFactory, priorityOrderedPostProcessors); // Next, register the BeanPostProcessors that implement. Ordered BeanPostProcessors List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size()); for (String ppName : orderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); orderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); } } sortPostProcessors(orderedPostProcessors, beanFactory); / / sorting registerBeanPostProcessors (the beanFactory, orderedPostProcessors); // Now, Register all regular BeanPostProcessors. // Register all regular BeanPostProcessors List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size()); for (String ppName : nonOrderedPostProcessorNames) { BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); nonOrderedPostProcessors.add(pp); if (pp instanceof MergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); }} / / registered registerBeanPostProcessors (the beanFactory, nonOrderedPostProcessors); // Finally, re-register all internal BeanPostProcessors. Register all conventional BeanPostProcessors (that is, to realize MergedBeanDefinitionPostProcessor BeanPostProcessors) sortPostProcessors(internalPostProcessors, beanFactory); / / sorting registerBeanPostProcessors (the beanFactory, internalPostProcessors); // Re-register the post-processor for detecting inner beans as ApplicationListeners, // moving it to the end of the processor chain (for picking up proxies etc). beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext)); / / add a ApplicationListenerDetector}Copy the code

The comments are written into the code. This method isn’t too complicated, but basically just one thing: Register BeanPostProcessors. Here is a flow chart of the entire approach:

MergedBeanDefinitionPostProcessor

In the method above, repeatedly appeared MergedBeanDefinitionPostProcessor, take a look at this interface is what; Let’s start with the class comment:

/** * Post-processor callback interface for <i>merged</i> bean definitions at runtime. * {@link BeanPostProcessor} implementations may implement this sub-interface in order * to post-process the merged bean definition (a processed copy Of the original bean * definition) that the Spring {@code BeanFactory} uses to create a bean instance. To merge bean information at run time. * BeanPostProcessor's implementation class implements this subinterface, To Spring The BeanFactory need to merge when creating The bean instance bean information (a The copy of The original bean information processed) * * < p > The {@ # link postProcessMergedBeanDefinition} method may for example introspect * the bean definition in order to prepare some cached metadata before post-processing * actual instances of a bean. It is also allowed to modify the bean definition but * <i>only</i> for definition properties  which are actually intended for concurrent * modification. Essentially, this only applies to operations defined on the * {@link RootBeanDefinition} itself but not to the properties of its base Classes. * postProcessMergedBeanDefinition this method can, for example: in order to rear in the actual instantiation of the bean processing before prepare some cache metadata to a custom bean information. * It also allows you to modify the bean definition, but only the definition properties that are actually used for concurrent modification. * Essentially, this applies only to operations defined on the RootBeanDefinition itself, not to the attribute * */ of its base classCopy the code

To sum up, you can modify some of the bean’s attribute information.

In this place actually registerBeanPostProcessors method (spring – the context 5.2.8), On the MergedBeanDefinitionPostProcessor a internalPostProcessors interface implementation class has two, one is AutowiredAnnotationBeanPostProcessor, One is CommonAnnotationBeanPostProcessor, here only wrote AutowiredAnnotationBeanPostProcessor, Actually CommonAnnotationBeanPostProcessor is mainly deal with the following a few, interested can go to see his concrete realization.

    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    import javax.annotation.Resource;
    import javax.ejb.EJB;
    import javax.xml.namespace.QName;
    import javax.xml.ws.Service;
    import javax.xml.ws.WebServiceClient;
    import javax.xml.ws.WebServiceRef;
Copy the code

AutowiredAnnotationBeanPostProcessor

This class is MergedBeanDefinitionPostProcessor implementation class, this class can be seen from the name above do automatic assembly.

A constructor
    public AutowiredAnnotationBeanPostProcessor() {
      this.autowiredAnnotationTypes.add(Autowired.class);
      this.autowiredAnnotationTypes.add(Value.class);
      try {
         this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
               ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
         logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
      }
      catch (ClassNotFoundException ex) {
         // JSR-330 API not available - simply skip.
      }
   }
Copy the code

The constructor is to add Autowired, Value, and Inject into autowiredAnnotationTypes.

PostProcessMergedBeanDefinition method
    @Override
   public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class
        beanType, String beanName) {
       // Query autowiring metadata
      InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
      // Check the configuration
      metadata.checkConfigMembers(beanDefinition);
   }
Copy the code
    private InjectionMetadata findAutowiringMetadata(String beanName, Class<? > clazz,@Nullable PropertyValues pvs) {
      // Fall back to class name as cache key, for backwards compatibility with custom callers.
      String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
      // Quick check on the concurrent map first, with minimal locking.
      InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
      if (InjectionMetadata.needsRefresh(metadata, clazz)) {
         synchronized (this.injectionMetadataCache) {
            metadata = this.injectionMetadataCache.get(cacheKey);
            if (InjectionMetadata.needsRefresh(metadata, clazz)) {
               if(metadata ! =null) {
                  metadata.clear(pvs);
               }
               metadata = buildAutowiringMetadata(clazz);
               this.injectionMetadataCache.put(cacheKey, metadata); }}}return metadata;
   }
Copy the code

The main process of this method is:

  1. Determine the cache
  2. lock
  3. Build a data
  4. Memory cache

The most important part of this method is the buildAutowiringMetadata method.


    private InjectionMetadata buildAutowiringMetadata(finalClass<? > clazz) {
      if(! AnnotationUtils.isCandidateClass(clazz,this.autowiredAnnotationTypes)) {
         return InjectionMetadata.EMPTY;
      }

      List<InjectionMetadata.InjectedElement> elements = newArrayList<>(); Class<? > targetClass = clazz;do {
          // Build currElements to store the data that meets the criteria
         final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
            // Iterate over the arguments of the current class
         ReflectionUtils.doWithLocalFields(targetClass, field -> {
             // Find the qualified parameters (that is, the three annotations in the constructor)MergedAnnotation<? > ann = findAutowiredAnnotation(field);if(ann ! =null) {
               if (Modifier.isStatic(field.getModifiers())) {
                  if (logger.isInfoEnabled()) {
                     logger.info("Autowired annotation is not supported on static fields: " + field);
                  }
                  return;
               }
               // Get the required parameter
               boolean required = determineRequiredStatus(ann);
               // Join if the conditions are met
               currElements.add(newAutowiredFieldElement(field, required)); }});// Iterate over all the methods of the current class
         ReflectionUtils.doWithLocalMethods(targetClass, method -> {
             // Find the method that matches the condition (same as above)
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
            if(! BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return; } MergedAnnotation<? > ann = findAutowiredAnnotation(bridgedMethod);if(ann ! =null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
               if (Modifier.isStatic(method.getModifiers())) {
                  if (logger.isInfoEnabled()) {
                     logger.info("Autowired annotation is not supported on static methods: " + method);
                  }
                  return;
               }
               if (method.getParameterCount() == 0) {
                  if (logger.isInfoEnabled()) {
                     logger.info("Autowired annotation should only be used on methods with parameters: "+ method); }}// Get the required parameter
               boolean required = determineRequiredStatus(ann);
               PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
               // Add to currElements
               currElements.add(newAutowiredMethodElement(method, required, pd)); }}); elements.addAll(0, currElements);
         targetClass = targetClass.getSuperclass();
      }
      while(targetClass ! =null&& targetClass ! = Object.class);// Iterate up until the parent class is Object.

      return InjectionMetadata.forElements(elements, clazz); / / return
   }
   
Copy the code

This method is mainly the following points:

  1. Keep going up until the parent class is zeroObjectSo far.
  2. Iterates through the class’s parameters and methods to find conditions (by@Autowired.@Value.@InjectModifier), and finally put into the collection
  3. Encapsulate the collection and return
    privateMergedAnnotation<? > findAutowiredAnnotation(AccessibleObject ao) { MergedAnnotations annotations = MergedAnnotations.from(ao);for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) { MergedAnnotation<? > annotation = annotations.get(type);if (annotation.isPresent()) {
            returnannotation; }}return null;
   }
Copy the code

This method iterates through the autowiredAnnotationTypes to see if the parameter or method is modified by an annotation in the autowiredAnnotationTypes.

Now that you’ve found the parameters and methods decorated with the appropriate annotations using the findAutowiringMetadata method, it’s time to execute the checkConfigMembers method. This method in the org. Springframework. Beans. Factory. The annotation. InjectionMetadata class.

    public void checkConfigMembers(RootBeanDefinition beanDefinition) {
      Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
      for (InjectedElement element : this.injectedElements) {
         Member member = element.getMember();
         if(! beanDefinition.isExternallyManagedConfigMember(member)) { beanDefinition.registerExternallyManagedConfigMember(member); checkedElements.add(element);if (logger.isTraceEnabled()) {
               logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]."+ element); }}}this.checkedElements = checkedElements;
   }
Copy the code

This method iterates through the data taken from the findAutowiringMetadata method, returns the encapsulated data, and finally puts it into the RootBeanDefinition, or bean definition information.

The last

At this point, the post-processing in Spring is registered, and it’s up to you to see when it’s called.