spring源码(五)ConfigurationClassPostProcessor

614 阅读5分钟

前言

在上一篇文章中提到了ConfigurationClassPostProcessor,下面看看ConfigurationClassPostProcessor在spring中充当了什么样的角色。

正文

源码版本:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.8.RELEASE</version>
    </dependency>

注释

首先要看的就是该类的注释了:

    /**
     * {@link BeanFactoryPostProcessor} used for bootstrapping processing of
     * {@link Configuration @Configuration} classes.
     * 被用来引导处理Configuration类型的类(也就是处理配置类,例如被@Configuration注解修饰的类)
     *
     * <p>Registered by default when using {@code <context:annotation-config/>} or
     * {@code <context:component-scan/>}. Otherwise, may be declared manually as
     * with any other BeanFactoryPostProcessor.
     * 使用<context:annotation-config/>或<context:component-scan/>时默认被注册(注册到spring容器中),
     * 反之,也可以像其他的BeanFactoryPostProcessor一样手动声明。
     *
     * <p>This post processor is priority-ordered as it is important that any
     * {@link Bean} methods declared in {@code @Configuration} classes have
     * their corresponding bean definitions registered before any other
     * {@link BeanFactoryPostProcessor} executes.
     * 这个后置处理是按优先级来排序的,还有一点很重要,就是在@Configuration标记的类(配置类)中声明的一些Bean方法,
     * 这些bean方法对应的bean信息会在一些其他的BeanFactoryPostProcessor执行前被注册。(例如自定义BeanFactoryPostProcessor的实现类)
     */

ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry

接下来就是BeanDefinitionRegistryPostProcessor接口中的方法,看看这个类实现这个接口去做了些什么。

    /**
    * Derive further bean definitions from the configuration classes in the registry.
    */
   @Override
   public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
      int registryId = System.identityHashCode(registry); // 一致性hash码
      if (this.registriesPostProcessed.contains(registryId)) { // 判断在registriesPostProcessed是否存在
         throw new IllegalStateException(
               "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
      }
      if (this.factoriesPostProcessed.contains(registryId)) {// 判断在factoriesPostProcessed是否存在
         throw new IllegalStateException(
               "postProcessBeanFactory already called on this post-processor against " + registry);
      }
      this.registriesPostProcessed.add(registryId);// 添加到registriesPostProcessed
      processConfigBeanDefinitions(registry); 
   }
   

这个方法代码相对比较简单,注释也写到代码中了,主要就是判断registry的一致性ID是否已经在PostProcessed中了(其实就是判断是否已经执行过了)

ConfigurationClassPostProcessor.processConfigBeanDefinitions

postProcessBeanDefinitionRegistry方法在最后调用了processConfigBeanDefinitions方法,,下面是processConfigBeanDefinitions方法:


    /**
    * Build and validate a configuration model based on the registry of
    * {@link Configuration} classes.
    */
   public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
       // 定义一个集合,用来收集配置信息
      List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
      // 获取所有已经注册的bean的name
      String[] candidateNames = registry.getBeanDefinitionNames();
            
        // 遍历这个集合,筛选出属于配置(Configuration)的bean信息
      for (String beanName : candidateNames) {
         BeanDefinition beanDef = registry.getBeanDefinition(beanName);
         if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
            if (logger.isDebugEnabled()) {
               logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
            }
         }
         else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
         }
      }

      // Return immediately if no @Configuration classes were found
      // 判断是否有配置信息,没得就返回了
      if (configCandidates.isEmpty()) {
         return;
      }

      // Sort by previously determined @Order value, if applicable
      // 将配置信息集合按照Order排序
      configCandidates.sort((bd1, bd2) -> {
         int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
         int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
         return Integer.compare(i1, i2);
      });

      // Detect any custom bean name generation strategy supplied through the enclosing application context
      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;
            }
         }
      }
        // 设置标准化环境
      if (this.environment == null) {
         this.environment = new StandardEnvironment();
      }

      // Parse each @Configuration class // 构建配置文件的解析器
      ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);
        // 将配置信息放入set集合(去重)
      Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
      // 已经转换的
      Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); 
      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(); // 清空缓存
         // 判断解析后注册的bean数量是否大于解析前的数量(这里绝大多数情况是大于的)
         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
      // 将ImportRegistry注册为bean,为了支持ImportAware配置类
      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();
      }
   }

上面的代码也比较简单,注释基本都注明到代码里面了。 其中最重要的就是ConfigurationClassParser这个类,从命名上就可以知道这个类是解析配置类的。 下面看看他是怎么去解析配置类的。

ConfigurationClassParser.parse方法

开始进入到org.springframework.context.annotation.ConfigurationClassParser#parse()

这个方法的代码也比较简单,就是判断config类的类型,然后再选择怎么解析。最后他们统一都是调用到了processConfigurationClass这个方法


    public void parse(Set<BeanDefinitionHolder> configCandidates) {
      for (BeanDefinitionHolder holder : configCandidates) {
         BeanDefinition bd = holder.getBeanDefinition();
         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();
   }

ConfigurationClassParser.processConfigurationClass

    protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
        // 这个地方处理@Conditional注解的,
      if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
         return;
      }
      ConfigurationClass existingClass = this.configurationClasses.get(configClass);
      if (existingClass != null) {
         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);
         }
      }
      // Recursively process the configuration class and its superclass hierarchy.
      SourceClass sourceClass = asSourceClass(configClass, filter);
      do {
         sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
      }
      while (sourceClass != null);
      this.configurationClasses.put(configClass, configClass);
   }

这个方法代码也比较简单,就没写注释,有两个点,一个是conditionEvaluator.shouldSkip,他主要就是处理@Conditional注解,这里就不去看具体实现了。 另一个就是 doProcessConfigurationClass方法, 这个方法就就直接定位到doProcessConfigurationClass方法。

ConfigurationClassParser.doProcessConfigurationClass

这个方法才是真正解析配置文件的核心所在。

    protected final SourceClass doProcessConfigurationClass(
         ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
         throws IOException {

        // 递归处理成员类,如果有成员类则递归调用processConfigurationClass处理
      if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
         // Recursively process any member (nested) classes first
         processMemberClasses(configClass, sourceClass, filter);
      }

      // Process any @PropertySource annotations // 处理@PropertySource注解
      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");
         }
      }

      // Process any @ComponentScan annotations
      // 处理ComponentScans和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());
               }
            }
         }
      }

      // Process any @Import annotations
      // 处理@Import注解
      processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

      // Process any @ImportResource annotations
      // 处理@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);
         }
      }

      // Process individual @Bean methods
      // 处理单个bean方法
      Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
      for (MethodMetadata methodMetadata : beanMethods) {
         configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
      }

      // Process default methods on interfaces
      // 处理接口默认方法
      processInterfaces(configClass, sourceClass);

      // Process superclass, if any
      // 超类处理,如果有的话
      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;
   }

下面是解析配置文件的流程图:

配置.png

ConfigurationClassPostProcessor.postProcessBeanFactory

ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,另一个实现方法就是postProcessBeanFactory

    @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       // 一致性hashcode
      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);// 添加进工厂中
      if (!this.registriesPostProcessed.contains(factoryId)) {
          // BeanDefinitionRegistryPostProcessor没被调用,这时懒加载调用就可以
         // BeanDefinitionRegistryPostProcessor hook apparently not supported...
         // Simply call processConfigurationClasses lazily at this point then.
         processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
      }
        // 增强配置类
      enhanceConfigurationClasses(beanFactory);
      // 注册ImportAwareBeanPostProcessor
      beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
   }

这个方法最重要的就是最后一行,注册ImportAwareBeanPostProcessor, 那么这个ImportAwareBeanPostProcessor是干什么的,这里只贴他的两个实现方法的代码:

        @Override
      public PropertyValues postProcessProperties(@Nullable PropertyValues pvs, Object bean, String beanName) {
         // Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
         // postProcessProperties method attempts to autowire other configuration beans.
         if (bean instanceof EnhancedConfiguration) {
            ((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
         }
         return pvs;
      }

      @Override
      public Object postProcessBeforeInitialization(Object bean, String beanName) {
         if (bean instanceof ImportAware) {
            ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
            AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
            if (importingClass != null) {
               ((ImportAware) bean).setImportMetadata(importingClass);
            }
         }
         return bean;
      }

其中postProcessProperties方法是处理EnhancedConfiguration接口的实现类的。 postProcessBeforeInitialization就是处理ImportAware接口实现类的。

最后

ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,其中postProcessBeanDefinitionRegistry方法主要是用来处理解析配置信息的, 而postProcessBeanFactory方法主要是是注册了ImportAwareBeanPostProcessor

其实在springboot的源码中,有很多的配置类,那些配置类就是被ConfigurationClassPostProcessor解析的。