Spring源码系列——ConfigurationClassPostProcessor源码解析

一. 前言

在这三篇文章以Java Config的启动方式系统的梳理了Spring在启动过程的源码解析。
Spring源码系列——容器的启动过程(一)

Spring源码系列——容器的启动过程(二)

Spring源码系列——容器的启动过程(三)

在这个过程中,见识了Spring当中的很多思想以及核心组件的使用。本篇文章将系统解析Spring后置处理器当中最核心的处理器之一: ConfigurationClassPostProcessor

二. UML类图

ConfigurationClassPostProcessor的UML类图如下:

UML类图

 

从UML类图中可以发现: ConfigurationClassPostProcessor实现了Aware接口,这意味着它不受Spring的生命周期管理,所以正常情况下开发者无法插足它的使用.只有Spring内部才能使用它. 最重要的是它实现了 BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor这两个接口. 在Spring源码系列——容器的启动过程(三) 中详细阐述了这两个接口之间的关系以及执行的优先级.这里不再赘述.

三. 代码入口

配置类

package com.leon.funddatahouse.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author created by leon on 2020-09-13
 * @since 版本号
 */
@Configuration
@ComponentScan("com.leon.funddatahouse.spring")
public class Config {

}
复制代码

入口

package com.leon.funddatahouse.spring;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author created by leon on 2020-09-13
 * @since 版本号
 */
public class MyApplication {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(Config.class);
    }
}

复制代码

四. 源码解析

如何执行到ConfigurationClassPostProcessorSpring源码系列——容器的启动过程(三) 有详细介绍, 这里不再赘述. 由于ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,因此:
先执行 BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry
再执行BeanFactoryPostProcessor#postProcessBeanFactory

4.1 postProcessBeanDefinitionRegistry() 源码解析

源码如下:

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
      int registryId = System.identityHashCode(registry);
      if (this.registriesPostProcessed.contains(registryId)) {
          throw new IllegalStateException(
                  "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
      }
      if (this.factoriesPostProcessed.contains(registryId)) {
          throw new IllegalStateException(
                  "postProcessBeanFactory already called on this post-processor against " + registry);
      }
      this.registriesPostProcessed.add(registryId);
      // 上面的代码都不重要,主要看这里.该方法才是核心方法
      processConfigBeanDefinitions(registry);
  }
复制代码

4.1.1 processConfigBeanDefinitions()才是核心

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
      // 用于盛放解析出来的config类的bdh
      List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
      // 从容器中获取所有bd name,在这里获取到的只有7个(Spring内部6个,自己的配置类1个.)
      String[] candidateNames = registry.getBeanDefinitionNames();

      // 循环遍历, 不放过任何一个符合条件的bd(实际上只有自己的配置类符合条件)
      for (String beanName : candidateNames) {
          // 根据beanName获取bd
          BeanDefinition beanDef = registry.getBeanDefinition(beanName);
          // 判断是否已经被判定为configurationClass. 
          // 从ConfigurationClassUtils类可知,如果是判断是否是configurationClass的话,该属性不为空.
          // 而刚进入到这里时,其属性一定为空,因此会走else if分支进一步判断
          if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
              if (logger.isDebugEnabled()) {
                  logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
              }
          }
          // 校验当前beanDef是否符合config候选条件. 具体如下:
          // 1.如果有@Configuration注解,则为deanDef添加属性 CONFIGURATION_CLASS_FULL,表示是一个完全配置类.
          // 2.如果没有@Configuration但是有@Bean/@Import等注解,则为beanDef添加属性 CONFIGURATION_CLASS_LITE,表示是一个简单的配置类.
          // 3.以上两点只要满足一点,就会返回true,如果二者都没有,则返回false
          else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
              configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
          }
      }

      // 经过遍历判断之后, 如果候选集合为空,则直接返回.
      if (configCandidates.isEmpty()) {
          return;
      }

      // Sort by previously determined @Order value, if applicable
      // 根据排序的值进行排序. 从UML类图可以得知,它实现了 @Ordered接口
      // 题外话: 排序值的设置可以通过@Order设置也可通过实现Ordered接口或者PriorityOrdered接口重写getOrder来实现
      configCandidates.sort((bd1, bd2) -> {
          int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
          int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
          return Integer.compare(i1, i2);
      });

      // 确定 bean name生成器, 简单,继续往下
      SingletonBeanRegistry sbr = null;
      if (registry instanceof SingletonBeanRegistry) {
          sbr = (SingletonBeanRegistry) registry;
          if (!this.localBeanNameGeneratorSet) {
              BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
                      AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
              if (generator != null) {
                  this.componentScanBeanNameGenerator = generator;
                  this.importBeanNameGenerator = generator;
              }
          }
      }

      // 设置environment, 简单, 继续往下.
      if (this.environment == null) {
          this.environment = new StandardEnvironment();
      }

      // 创建@Configuration 的解析器
      ConfigurationClassParser parser = new ConfigurationClassParser(
              this.metadataReaderFactory, this.problemReporter, this.environment,
              this.resourceLoader, this.componentScanBeanNameGenerator, registry);

      // 将所有待解析的数组放在set集合中,达到去重的目的
      Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
      // 将解析完成的beanDef放在这个集合中
      Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
      
      // 递归解析 重要!!!
      // 采用do...while的方式, 因为在解析的过程中,可能会发现新的需要解析的@Configuration class.
      // 比如在解析出来的bean当中也有打上@Configuration注解的.这时需要重新比较所有的beanDef和已解析的beanDef来筛选出
      // 新发现的Configuration class,并将其添加到候选集合中, 这样while的判断成立,将会进行新的一轮解析.
      // 周而复始,直到将所有的@Configuration class解析完.
      // 完成这一切的关键就在于解析器的parse方法!
      do {
          parser.parse(candidates);
          parser.validate();

          Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
          configClasses.removeAll(alreadyParsed);

          // Read the model and create bean definitions based on its content
          if (this.reader == null) {
              this.reader = new ConfigurationClassBeanDefinitionReader(
                      registry, this.sourceExtractor, this.resourceLoader, this.environment,
                      this.importBeanNameGenerator, parser.getImportRegistry());
          }
          this.reader.loadBeanDefinitions(configClasses);
          alreadyParsed.addAll(configClasses);

          candidates.clear();
          if (registry.getBeanDefinitionCount() > candidateNames.length) {
              String[] newCandidateNames = registry.getBeanDefinitionNames();
              Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
              Set<String> alreadyParsedClasses = new HashSet<>();
              for (ConfigurationClass configurationClass : alreadyParsed) {
                  alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
              }
              for (String candidateName : newCandidateNames) {
                  if (!oldCandidateNames.contains(candidateName)) {
                      BeanDefinition bd = registry.getBeanDefinition(candidateName);
                      if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                              !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                          candidates.add(new BeanDefinitionHolder(bd, candidateName));
                      }
                  }
              }
              candidateNames = newCandidateNames;
          }
      }
      while (!candidates.isEmpty());

      // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
      if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
          sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
      }

      if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
          // Clear cache in externally provided MetadataReaderFactory; this is a no-op
          // for a shared cache since it'll be cleared by the ApplicationContext.
          ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
      }
  }
复制代码

4.1.2 ConfigurationClassParser#parse()方法源码解析

public void parse(Set<BeanDefinitionHolder> configCandidates) {
    // 循环遍历候选者
    for (BeanDefinitionHolder holder : configCandidates) {
        BeanDefinition bd = holder.getBeanDefinition();
        // 这里将根据BeanDefinition的具体类型来选择具体的解析方法.
        // 在这里, Config.class是是通过注解的方式, 因此进入if分支.
        try {
            if (bd instanceof AnnotatedBeanDefinition) {
                parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
            } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
                parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
            } else {
                parse(bd.getBeanClassName(), holder.getBeanName());
            }
        } catch (BeanDefinitionStoreException ex) {
            throw ex;
        } catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                    "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
        }
    }

    this.deferredImportSelectorHandler.process();
}

// ------------------分割线-----------------------
// 实际调用的重载版本是这个:
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
    // 继续委托
    processConfigurationClass(new ConfigurationClass(metadata, beanName));
}


// ------------------分割线-----------------------
// 核心方法
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
    // 根据条件解析器来判断当前的configClass是否需要跳过解析
    // 在这里Config.class不需要跳过解析, 因此if分支
    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
        return;
    }

    // 判断是否是正在解析的config class, 如果是,则直接返回
    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
    if (existingClass != null) {
        // 这里判断是是否有@Import
        if (configClass.isImported()) {
            if (existingClass.isImported()) {
                existingClass.mergeImportedBy(configClass);
            }
            // Otherwise ignore new imported config class; existing non-imported class overrides it.
            return;
        } else {
            // Explicit bean definition found, probably replacing an import.
            // Let's remove the old one and go with the new one.
            this.configurationClasses.remove(configClass);
            this.knownSuperclasses.values().removeIf(configClass::equals);
        }
    }

    // 递归解析. 重要!!!
    SourceClass sourceClass = asSourceClass(configClass);
    do {
        sourceClass = doProcessConfigurationClass(configClass, sourceClass);
    }
    while (sourceClass != null);

    this.configurationClasses.put(configClass, configClass);
}
复制代码

4.1.3 doProcessConfigurationClass()源码解析

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
        throws IOException {
    // 判断是否有@Component注解. @Configuration注解嵌套了@Component注解,因此进入if分支进行处理.
    if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
        processMemberClasses(configClass, sourceClass);
    }
    
    // 处理解析@PropertySource和@PropertySources.
    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), PropertySources.class,
            org.springframework.context.annotation.PropertySource.class)) {
        if (this.environment instanceof ConfigurableEnvironment) {
            processPropertySource(propertySource);
        } else {
            logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                    "]. Reason: Environment must implement ConfigurableEnvironment");
        }
    }

    // 处理解析 @ComponentScan
    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
    if (!componentScans.isEmpty() &&
            !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
        for (AnnotationAttributes componentScan : componentScans) {
            // The config class is annotated with @ComponentScan -> perform the scan immediately
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // Check the set of scanned definitions for any further config classes and parse recursively if needed
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }

    // 处理解析 @Import
    processImports(configClass, sourceClass, getImports(sourceClass), true);

    // 处理解析 @ImportResource
    AnnotationAttributes importResource =
            AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
    if (importResource != null) {
        String[] resources = importResource.getStringArray("locations");
        Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
        for (String resource : resources) {
            String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
            configClass.addImportedResource(resolvedResource, readerClass);
        }
    }

    // 处理解析 @Bean
    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
    for (MethodMetadata methodMetadata : beanMethods) {
        configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
    }

    // 处理接口上的默认方法,将其加到bd的beanMethods中
    processInterfaces(configClass, sourceClass);

    // 如果有父类,则返回父类Class,上一层方法会进行递归处理
    if (sourceClass.getMetadata().hasSuperClass()) {
        String superclass = sourceClass.getMetadata().getSuperClassName();
        if (superclass != null && !superclass.startsWith("java") &&
                !this.knownSuperclasses.containsKey(superclass)) {
            this.knownSuperclasses.put(superclass, configClass);
            // Superclass found, return its annotation metadata and recurse
            return sourceClass.getSuperClass();
        }
    }

    // No superclass -> processing is complete
    return null;
}
复制代码

从这里可以看出,如果配置类上使用了@Configuration注解,那么Spring会将@ComponentScan / @Import/@Bean / @PropertySource / @ImportResource 等一并解析,(如果加了这些注解的话). 我们知道,@ComponentScan等注解都是Spring 当中的基本且重要的"配置类型"的注解. 这里就说明了为什么@Configration注解时,deanDef的属性值为 ConfigurationClassUtils.CONFIGURATION_CLASS_FULL,这说明它可以被当做是一个"完全"配置类来解析. 关于@ComponentScan / @Import/@Bean / @PropertySource / @ImportResource.

4.1.4 @ComponentScan解析

从上面的源码中可以看出,解析@ComponentScan的核心代码是:

Set<BeanDefinitionHolder> scannedBeanDefinitions = 
    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
复制代码

我们来探究一波这个parse方法!

4.1.5 ComponentScanAnnotationParser#parse源码解析

从类名就可以看出, ComponentScanAnnotationParser类是专门用于解析扫描并解析工程中@Componet注解的.其parse源码如下:

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {

    //创建一个scanner. 简单,继续往下
    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
            componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);

    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
            BeanUtils.instantiateClass(generatorClass));

    // 判断并设置scopedProxyMode. 简单,继续往下
    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
    if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
        scanner.setScopedProxyMode(scopedProxyMode);
    }
    else {
        Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
        scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
    }

    // 设置资源路径. 简单,继续往下
    scanner.setResourcePattern(componentScan.getString("resourcePattern"));

    // 设置includeFilters
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            scanner.addIncludeFilter(typeFilter);
        }
    }
    // 设置excludeFilters. 简单,继续往下
    for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
        for (TypeFilter typeFilter : typeFiltersFor(filter)) {
            scanner.addExcludeFilter(typeFilter);
        }
    }

    // 设置lazyInit属性. 简单,继续往下
    boolean lazyInit = componentScan.getBoolean("lazyInit");
    if (lazyInit) {
        scanner.getBeanDefinitionDefaults().setLazyInit(true);
    }

    // 扫描的包路径. 简单,继续往下
    Set<String> basePackages = new LinkedHashSet<>();
    String[] basePackagesArray = componentScan.getStringArray("basePackages");
    for (String pkg : basePackagesArray) {
        String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
                ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
        Collections.addAll(basePackages, tokenized);
    }
    for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
        basePackages.add(ClassUtils.getPackageName(clazz));
    }
    if (basePackages.isEmpty()) {
        basePackages.add(ClassUtils.getPackageName(declaringClass));
    }

    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
        @Override
        protected boolean matchClassName(String className) {
            return declaringClass.equals(className);
        }
    });

    // 开始扫描. 重要!!!
    return scanner.doScan(StringUtils.toStringArray(basePackages));
}
复制代码

4.1.6 ClassPathBeanDefinitionScanner#doScan源码解析

终于见到庐山真面目,doScan方法完成了包路径的扫描并吧符合条件的类生成BeanDefinition.

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    Assert.notEmpty(basePackages, "At least one base package must be specified");
    // 初始化一个bd set,用于盛放即将扫描并解析出来的bd!
    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
    
    // 遍历循环
    for (String basePackage : basePackages) {
        // 重要!!! 该方法便是去读取包路径下的资源,并解析出该包下所有符合条件的类生成bd.
        // 本质上还是通过流的方式读取class文件然后对class对象进行解析并生成bd的.
        // 看似高深莫测,实则 大道至简!
        Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
        // 对当前包下的bd进行遍历加工,然后注册到BeanFactory中去!
        for (BeanDefinition candidate : candidates) {
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
                postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
                AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            if (checkCandidate(beanName, candidate)) {
                BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                definitionHolder =
                        AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                beanDefinitions.add(definitionHolder);
                registerBeanDefinition(definitionHolder, this.registry);
            }
        }
    }
    return beanDefinitions;
}
复制代码

4.2 postProcessBeanFactory源码解析

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    int factoryId = System.identityHashCode(beanFactory);
    if (this.factoriesPostProcessed.contains(factoryId)) {
        throw new IllegalStateException(
                "postProcessBeanFactory already called on this post-processor against " + beanFactory);
    }
    this.factoriesPostProcessed.add(factoryId);
    // 判断factoryId是否改变,如果改变,重新走一遍~~~
    if (!this.registriesPostProcessed.contains(factoryId)) {
        processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
    }

    // 使用Cglib动态代理来增强配置类. 重要!!!
    enhanceConfigurationClasses(beanFactory);
    beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
复制代码
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {

    // 找到所有配置类
    Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
        Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
        MethodMetadata methodMetadata = null;
        if (beanDef instanceof AnnotatedBeanDefinition) {
            methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
        }
        if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
            // Configuration class (full or lite) or a configuration-derived @Bean method
            // -> resolve bean class at this point...
            AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
            if (!abd.hasBeanClass()) {
                try {
                    abd.resolveBeanClass(this.beanClassLoader);
                }
                catch (Throwable ex) {
                    throw new IllegalStateException(
                            "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
                }
            }
        }
        
        
        // 判断是否是"完全"配置类,即@Configuration的配置类
        if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
            if (!(beanDef instanceof AbstractBeanDefinition)) {
                throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                        beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
            }
            else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
                logger.info("Cannot enhance @Configuration bean definition '" + beanName +
                        "' since its singleton instance has been created too early. The typical cause " +
                        "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
                        "return type: Consider declaring such methods as 'static'.");
            }
            configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
        }
    }
    
    // 没有"full"配置类,则直接返回
    if (configBeanDefs.isEmpty()) {
        // nothing to enhance -> return immediately
        return;
    }

    // 对"full"配置类进行增强,改变它的beanClass.
    ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
        AbstractBeanDefinition beanDef = entry.getValue();
        // If a @Configuration class gets proxied, always proxy the target class
        beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
        // Set enhanced subclass of the user-specified bean class
        Class<?> configClass = beanDef.getBeanClass();
        Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
        if (configClass != enhancedClass) {
            if (logger.isTraceEnabled()) {
                logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
                        "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
            }
            beanDef.setBeanClass(enhancedClass);
        }
    }
}
复制代码

为什么要对"full"配置类进行增强?

继续跟踪源码,可以发现其对应的方法拦截器为: BeanMethodInterceptorBeanFactoryAwareMethodInterceptor. 这两个方法拦截器主要是针对于@Bean方法的调用行为处理和FactoryBean#getOjbect行为的处理.具体为啥这样弄,我实在肝不动了~~我觉得这篇文章剖析的很好!

动态代理是非常重要的基础性知识.必须掌握 !!!

五. 总结

本篇文章对ConfigurationClassPostProcessor类进行了较为详细的源码跟踪和解读. 它对于整个Spring框架可谓重中之重.
解析该后置处理之前,需要先熟悉整个Spring容器的启动过程,才能知道它的执行触发机制; 需要掌握@Configuration的基本概念和应用;需要对动态代理以及后置处理器有基本的概念. 这样在剖析源码时才能游刃有余.
通过本篇文章,知道了Spring是如何扫描项目中的类并变成BeanDefinition的.同时初步窥探了Spring当中的动态代理技术的应用.


作者:浪漫先生


 

猜你喜欢

转载自blog.csdn.net/m0_50180963/article/details/108586813