Spring源码解析之ConfigurationClassPostProcessor

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());
      }
      
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring源码解析是指对Spring框架的源代码进行深入分析和解读的过程。Spring框架是一个开源的Java企业级应用程序框架,提供了高度灵活和可扩展的开发环境。 Spring框架的源代码解析涉及了众多的模块和组件,包括核心容器、AOP(面向切面编程)、数据访问、Web开发等。通过对这些模块和组件的源代码进行解析,我们可以更加深入地了解Spring框架的工作原理和设计思想。 Spring源码解析的好处在于,可以帮助我们更好地理解Spring框架的各种功能和特性,并且能够帮助开发人员更加高效地使用和定制Spring框架,解决实际项目开发中的问题。 在进行Spring源码解析时,我们可以关注一些关键的概念和类,比如BeanFactory、ApplicationContext、BeanPostProcessor、AOP代理等。这些核心类和概念是理解Spring框架工作机制的重要基础。 进行Spring源码解析时,我们可以使用一些常见的工具和方法,比如IDE(集成开发环境)的调试功能、查看和分析源代码的注释和文档、调试和运行项目的示例代码等。 通过Spring源码解析,我们可以学到很多有关软件开发的知识和经验,比如面向对象编程、设计模式、依赖注入、控制反转等。这些知识和经验对于我们提升自己的技术水平和解决实际项目中的问题都有很大的帮助。 总之,Spring源码解析是一项非常有价值的学习和研究工作,可以帮助我们更好地理解和应用Spring框架,提高自己的技术能力和软件开发水平。希望以上的回答能够满足您的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值