springboot源码(四)自动装配ConfigurationClassPostProcessor

198 阅读3分钟

spring自动装配-ConfigurationClassPostProcessor

ConfigurationClassPostProcessor类关系图 image-20220429214753027.png 其实这个类的关系图并没有什么复杂点,我们只需要关注他是一个BeanDefinitionRegistryPostProcessor即可,Aware是用来获得spring关键对象的,Ordered用来确定其多个BeanDefinitionRegistryPostProcessor时的执行顺序

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
   // 对bean工厂生成一个hashId
   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);
   // 为工厂添加BeanDefinition
   processConfigBeanDefinitions(registry);
}

postProcessBeanDefinitionRegistry的核心作用就是为工厂生产跟多的BeanDefinition,所以processConfigBeanDefinitions方法直接丢了一个bean工厂进去。

这里放置了一个id,目前不知道干啥的,继续往下看processConfigBeanDefinitions方法

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
   List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
   String[] candidateNames = registry.getBeanDefinitionNames();
​
   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);
         }
      }
       // checkConfigurationClassCandidate先判断是否时需要过滤的类,是的话返回false
       // 去做全配置类和半配置类的标识,然后返回true
       else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
         configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
      }
   }
   // 如果配置候选列表是空,那直接返回
   if (configCandidates.isEmpty()) {
      return;
   }
   //排序
   configCandidates.sort((bd1, bd2) -> {
      int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
      int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
      return Integer.compare(i1, i2);
   });
​
   // 设置一下bean的命名策略类
   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();
   }
   // 创建解析器
   ConfigurationClassParser parser = new ConfigurationClassParser(
         this.metadataReaderFactory, this.problemReporter, this.environment,
         this.resourceLoader, this.componentScanBeanNameGenerator, registry);
​
   Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
   // 存放已经解析的ConfigurationClass
   Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
   do {
      StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
      // 解析,很重要
      parser.parse(candidates);
      // 校验
      parser.validate();
      // 把解析器里的configClasses的configurationClasses拿出来
      Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
      // 去掉已经加载的类
      configClasses.removeAll(alreadyParsed);
      // 此时configClasses只要没加载过的
      // 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());
      }
      // 加载bandDefinition
      this.reader.loadBeanDefinitions(configClasses);
      alreadyParsed.addAll(configClasses);
      processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
      // 清理candidates,不然会死循环
      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
               BeanDefinition bd = registry.getBeanDefinition(candidateName);
               // 判断是否是配置类,并且还未解析是的话放入candidates(此时为null)
               if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
                     !alreadyParsedClasses.contains(bd.getBeanClassName())) {
                  candidates.add(new BeanDefinitionHolder(bd, candidateName));
               }
            }
         }
         candidateNames = newCandidateNames;
      }
   }
   // 如果产生了新的candidates会一直循环,直到为止
   while (!candidates.isEmpty());
   // 注册 ImportRegistry 为一个bean来支持 @Configuration
   if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
      sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
   }
   if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
      // 清理缓存
      ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
   }
}

此方法有一个do-while循环,核心代码就是parse方法,也是的自动化装配的关键,它能够解析所有配置类

1 校验是否是配置类

checkConfigurationClassCandidate(删减版)这这里会被频繁调用,所以进行一下简单解析

public static final String CONFIGURATION_CLASS_FULL = "full";
public static final String CONFIGURATION_CLASS_LITE = "lite";
​
public static final String CONFIGURATION_CLASS_ATTRIBUTE =
            Conventions.getQualifiedAttributeName(ConfigurationClassPostProcessor.class, "configurationClass");
​
public static boolean checkConfigurationClassCandidate(
      BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
​
   String className = beanDef.getBeanClassName();
   if (className == null || beanDef.getFactoryMethodName() != null) {
      return false;
   }
   AnnotationMetadata metadata;
   if (beanDef instanceof AnnotatedBeanDefinition &&
         className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
      // Can reuse the pre-parsed metadata from the given BeanDefinition...
      metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
   }else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
      // 去除这些内置类,spring认为他们不是配置类
      if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
            BeanPostProcessor.class.isAssignableFrom(beanClass) ||
            AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
            EventListenerFactory.class.isAssignableFrom(beanClass)) {
         return false;
      }
      metadata = AnnotationMetadata.introspect(beanClass);
   }
   Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
   // 设置属性
   if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
      // 设置为全配置类,后续为其生产代理
      beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
   }
   else if (config != null || isConfigurationCandidate(metadata)) {
      // 甚至为半配置类
      beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
   }
   else {return false;}
   return true;
}

这里做了一个属性的赋值,用来标注是否是配置类,如果是配置类又分为两类:

A full 全配置类:标注了@Configuration注解的

B lite 半配置类:标注了@Component、@ComponentScan、@Import、@ImportResource的类或者@Bean注解的方法

2 解析

parse方法通过一层层分装,最终调用的还是processConfigurationClass方法

继续往下看processConfigurationClass方法

private final Map<ConfigurationClass, ConfigurationClass> configurationClasses = new LinkedHashMap<>();
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
   // 省略一些不太重要的判断代码
   // 获取源类
   SourceClass sourceClass = asSourceClass(configClass, filter);
   do {
      // 获取configClass
      sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
   }
   while (sourceClass != null);
   // 把产生的configClass放入configurationClasses供后续解析器解析
   this.configurationClasses.put(configClass, configClass);
}

这里有个非常疑惑的点,为什么configurationClasses设计成map,key和value完全一致,可能是后续方便取出(瞎猜的)

2.1 递归解析配置类

doProcessConfigurationClass

继续往下看doProcessConfigurationClass方法(删减版)

@Nullable
protected final SourceClass doProcessConfigurationClass(
      ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
      throws IOException {
  // 解析@Component注解
   if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
      processMemberClasses(configClass, sourceClass, filter);
   }
   // 解析@PropertySource注解
   for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
         sourceClass.getMetadata(), PropertySources.class,
         org.springframework.context.annotation.PropertySource.class)) {
      if (this.environment instanceof ConfigurableEnvironment) {
         processPropertySource(propertySource);
      }
      else {}
   }
   // 解析@ComponentSca注解
   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) {
         Set<BeanDefinitionHolder> scannedBeanDefinitions =
               this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
         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), filter, 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));
   }
   // 解析接口
   processInterfaces(configClass, sourceClass);
   // 解析父类
   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();
      }
   }
   // 执行完会返回null
   return null;
}

doProcessConfigurationClass方法内部实现非常复杂,同时也非常的巧妙,大量使用递归,同时解析父类时,通过返回值来控制上层方法不断do-while。

3 加载BeanDefinition

loadBeanDefinitions

最令我疑惑的是在执行loadBeanDefinitions方法之前又把configurationClasses这个key-value相同的map转成了set(为什么不一开始就使用map呢)

image-20220430005854024.png

上图展示了ConfigurationClass的基本字段

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
   TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
   // 循环 配置configClass
   for (ConfigurationClass configClass : configurationModel) {
      loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
   }
}

loadBeanDefinitionsForConfigurationClass方法如下

private void loadBeanDefinitionsForConfigurationClass(
      ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
   // 判断是否需要调过
   if (trackedConditionEvaluator.shouldSkip(configClass)) {
      String beanName = configClass.getBeanName();
      if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
         this.registry.removeBeanDefinition(beanName);
      }
      this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
      return;
   }
   if (configClass.isImported()) {
      //  处理@Import导入的
      registerBeanDefinitionForImportedConfigurationClass(configClass);
   }
   for (BeanMethod beanMethod : configClass.getBeanMethods()) {
      // 处理方法上bean注解的
      loadBeanDefinitionsForBeanMethod(beanMethod);
   }
   // 处理@ImportResource导入的
   loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
   // 处理实现 ImportBeanDefinitionRegistrar接口的
   loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

这里又再一次出现了我们熟悉的registry,如果要添加beanDefinition那一定是需要往bean工厂里放的

下篇我会对doProcessConfigurationClass方法再做一次详细的解析,欣赏一下spring代码的优美