Spring源码解析之ConfigurationClassPostProcessor

本文详细解析了Spring的ConfigurationClassPostProcessor处理过程,包括@Conditional条件判断、@Component组件扫描、@PropertySource属性来源、@ComponentScan的类扫描、@Import导入机制以及@ImportResource资源导入。同时,深入探讨了@Bean的解析和DeferredImportSelector的处理。
摘要由CSDN通过智能技术生成

ConfigurationClassPostProcessor

调用入口为AbstractApplicationContext#invokeBeanFactoryPostProcessors,在这个方法里面收集了所有BeanDefinitionRegistryPostProcessors实现类,并调用postProcessBeanDefinitionRegistry方法。我们来看下ConfigurationClassPostProcessor#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);

   //核心逻辑,重点看,重要程度5
   processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
   
   List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
   //获取所有的beanNames
   String[] candidateNames = registry.getBeanDefinitionNames();

   for (String beanName : candidateNames) {
   
      BeanDefinition beanDef = registry.getBeanDefinition(beanName);
      // ...
      //判断是否是候选的需要处理的BeanDefinition,如果是则放入容器configCandidates
      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
   //对需要处理的所有beanDefinition排序
   configCandidates.sort((bd1, bd2) -> {
   
      int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
      int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
      return Integer.compare(i1, i2);
   });

   // ...

}

检查bean是否是配置类:@Configuration/@Component/@ComponentScan/@Import/@ImportResouce/方法上有@Bean

public static boolean checkConfigurationClassCandidate(
      BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
   

   String className = beanDef.getBeanClassName();
   if (className == null || beanDef.getFactoryMethodName() != null) {
   
      return false;
   }

   AnnotationMetadata metadata;
   //如果是扫描注解产生的BeanDefinition,比如通过@Component扫描出来的BeanDefinition
   if (beanDef instanceof AnnotatedBeanDefinition &&
         className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
   
      //...
   }
   // 这里一般是spring内部的一些PostProcessor或者其他一些类
   else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
   
      //...
   }
   else {
    // 其他,比如通过xml解析出来的BeanDefinition
			try {
   
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				metadata = metadataReader.getAnnotationMetadata();
			}
			// ...
		}

   //从metadata中获取Configuration注解
   Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
   // 如果有Configuration注解,并且proxyBeanMethods=true,就是完全匹配标识
   // 这里有两种类型:full和lite,借用手机行业里的比喻:full就是高配版、lite就是低配版、青春版
   if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
   
      beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
   }
   // 如果是有Component ComponentScan Import ImportResource或者方法上面有@Bean,就是lite匹配
   else if (config != null || isConfigurationCandidate(metadata)) {
    // 这里要看下
      beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
   }
   else {
   
      // 如果都不是,那么就不是候选的bean了。
      return false;
   }

   //获取@Order注解值
   // It's a full or lite configuration candidate... Let's determine the order value, if any.
   Integer order = getOrder(metadata);
   if (order != null) {
   
      beanDef.setAttribute(ORDER_ATTRIBUTE, order);
   }

   return true;
}

判断bean是否有候选的注解修饰:Component ComponentScan Import ImportResource或是否方法上有@Bean

public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
   
   // Do not consider an interface or an annotation...
   if (metadata.isInterface()) {
   
      return false;
   }

   // 是否有被这些候选的注解修饰:Component ComponentScan Import ImportResource
   for (String indicator : candidateIndicators) {
   
      if (metadata.isAnnotated(indicator)) {
   
         return true;
      }
   }

   // 是否方法上有@Bean
   try {
   
      return metadata.hasAnnotatedMethods(Bean.class.getName());
   }
}

候选的注解:Component ComponentScan Import ImportResource

private static final Set<String> candidateIndicators = new HashSet<>(8);

static {
   
   candidateIndicators.add(Component.class.getName());
   candidateIndicators.add(ComponentScan.class.getName());
   candidateIndicators.add(Import.class.getName());
   candidateIndicators.add(ImportResource.class.getName());
}

判断完成后,我们就知道bean是否是候选bean。我么继续看processConfigBeanDefinitions方法。

	 // 候选BeanDefinition的解析器
   // Parse each @Configuration class
   ConfigurationClassParser parser = new ConfigurationClassParser(
         this.metadataReaderFactory, this.problemReporter, this.environment,
         this.resourceLoader, this.componentScanBeanNameGenerator, registry);

   Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
   Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
   do {
   
      //解析核心流程,重点看,重要程度5
      //其实就是把类上面的特殊注解解析出来最终封装成beanDefinition
      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());
      }
      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值