【小家Spring】Spring解析@ComponentScan注解源码分析(ComponentScanAnnotationParser、ClassPathBeanDefinitionScanner)

您所在的位置:网站首页 ComponentScan发音 【小家Spring】Spring解析@ComponentScan注解源码分析(ComponentScanAnnotationParser、ClassPathBeanDefinitionScanner)

【小家Spring】Spring解析@ComponentScan注解源码分析(ComponentScanAnnotationParser、ClassPathBeanDefinitionScanner)

2024-07-17 00:00| 来源: 网络整理| 查看: 265

前言

前面我在这篇博文:【小家Spring】Spring解析@Configuration注解的处理器:ConfigurationClassPostProcessor(ConfigurationClassParser) 解释Spring解析@Configuration的时候,提到过了解析:@PropertySource、@ComponentScan、@Import…等等的解析过程。

它在这个类里大概如下:ConfigurationClassParser#doProcessConfigurationClass:

代码语言:javascript复制protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass){ //1、Process any @PropertySource annotations //2、Process any @ComponentScan annotations === ==== 这一步解析,现在就是我们今天的主题,下面会对源码进行分析 ==== //3、Process any @Import annotations //4、Process any @ImportResource annotations //5、Process individual @Bean methods //6、Process default methods on interfaces //7、Process superclass, if any }

因为扫描模式在应用(我们自己在涉及自己的框架的时候,扫描模式也会被大量的、广泛的应用)使用非常的广泛,因此本文有必要来说说@ComponentScan的原理,旨在掌握它的运行过程,然后学以致用。

Spring Boot默认扫描Bean的处理,就是基于@ComponentScan这个注解的

源码分析入口处源码

前言部分已经提到了入口处,因此这里直接贴出此部分的源码吧:

代码语言:javascript复制 // Process any @ComponentScan annotations // 拿到该类上面所有的@ComponentScan注解,包含重复注解 Set 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 // 最终委托给了componentScanParser去完成这件事:至于componentScanParser是什么呢?下面有解释 // 备注:这个方法虽然有返回值,但是其实内部都已经把Bean定义信息加入到工厂里面去了 Set scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); // Check the set of scanned definitions for any further config classes and parse recursively if needed //这里面有一个重要的一步,还需要把每个Bean检测一遍。因为Scan出来的Bean,还有可能是@Configuration的,或者标注有@Import等等一些列注解的,因此需要再次交给parse一遍,防止疏漏 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()); } } } } `componentScanParser`是什么呢? private final ComponentScanAnnotationParser componentScanParser; // 然后在ConfigurationClassParser的构造函数里,对他进行了初始化 public ConfigurationClassParser(MetadataReaderFactory metadataReaderFactory, ProblemReporter problemReporter, Environment environment, ResourceLoader resourceLoader, BeanNameGenerator componentScanBeanNameGenerator, BeanDefinitionRegistry registry) { this.metadataReaderFactory = metadataReaderFactory; this.problemReporter = problemReporter; this.environment = environment; this.resourceLoader = resourceLoader; this.registry = registry; // 这里对componentScanParser 进行初始化。持有环境、ResourceLoader、名字生成器、注册器的引用 this.componentScanParser = new ComponentScanAnnotationParser(environment, resourceLoader, componentScanBeanNameGenerator, registry); // 初始化condition的计算器,持有注册器、环境、ResourceLoader的引用 this.conditionEvaluator = new ConditionEvaluator(registry, environment, resourceLoader); }ComponentScanAnnotationParser:准们解析@ComponentScan的类

从访问权限(Default)来看,它被定义为Spring的一个自己内部使用的工具类。它的惟一一个public方法为:parse():

代码语言:javascript复制 public Set parse(AnnotationAttributes componentScan, final String declaringClass) { // 第一句代码就看出了端倪:原来扫描的工作最终还是委托给了ClassPathBeanDefinitionScanner去做 // 注意:useDefaultFilters这个值特别的重要,能够解释伙伴们为何要配置的原因~~~下面讲解它的时候会有详解 ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry, componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader); // BeanName的生成器,我们可以单独制定。若不指定(大部分情况下都不指定),那就是默认的AnnotationBeanNameGenerator // 它的处理方式是:类名首字母小写 Class


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3