Spring源码之基于@ComponentScan生成BeanDefinition

一、前言

本文用到的是Spring5.2.4版本的源码。

Spring会根据配置类上@ComponentScan注解提供的扫描路径加载Bean,扫描加载的核心方法是ClassPathBeanDefinitionScanner.doScan()

在讲一下这个核心方法是在spring启动中的哪个环节执行的。

SpringBoot环境

主入口类的@SpringBootApplication注解中就包含@SpringBootConfiguration(可以理解成@Configuration的子类注解)和@ComponentScan注解,扫描的路径默认是当前主入口类的所在包。

在refresh()中的invokeBeanFactoryPostProcessors(beanFactory);中执行。invokeBeanFactoryPostProcessors负责执行所有的BeanFactoryPostProcessor。而派生类ConfigurationClassPostProcessor负责处理所有的@Configuration配置类。其中有一个环节是处理配置上的@ComponentScan注解,就会调用到我们上面说的核心方法doScan().

二、主要流程

doScan(): 生成并设置BeanDefinition
在这里插入图片描述

流程如下:

  1. 调用findCandidateComponents()找到所有的BeanDefinition候选者Set
  2. 遍历所有的BeanDefinition候选者
  3. 获取@Scope注解的信息并给BeanDefinition设置Scope属性
  4. 获取Bean的名字
  5. 添加些默认的Bean定义信息
  6. 解析@Lazy、@Primary、@DependsOn、@Role、@Description注解的信息
  7. 封装成BeanDefinitionHolder
  8. 根据Scope中的proxyMode判断是否需要创建代理
  9. 注册到beanDefinitionMap

findCandidateComponents(): 是doScan中的一个主要方法,作用是加载并过滤所有的class,得到BeanDefinition的全部候选者,生成beanDefinition。
在这里插入图片描述
流程如下:
11. 获取扫描的路径
12. 获取符合规则的所有class的Resource
13. 根据Resource获取MetadataReader
14. 根据excludeFilters、includeFilters以及@Conditional过滤MetadataReader
15. 基于metadataReader生成ScannedGenericBeanDefinition
16. 根据MetadataReader过滤BeanDefinition,过滤掉接口,过滤掉内部类,过滤掉没有@Lookup方法的抽象类
17. 将符合条件的BeanDefinition填加到集合中

三、源码解析

doScan:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        // basePackages为空抛出异常
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		// 定义BeanDefinitionHolder的集合
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		// 遍历扫描路径
		for (String basePackage : basePackages) {
		    // 找出所有的BeanDefinition候选者
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			// 遍历所有的BeanDefinition
			for (BeanDefinition candidate : candidates) {
			    // 读取@Scope注解的信息
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				// 设置Scope
				candidate.setScope(scopeMetadata.getScopeName());
				// 获取bean的名字
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				// 设置一些默认信息,例如默认的initmethod、destroymethod
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				// 解析@Lazy、@Primary、@DependsOn、@Role、@Description注解的信息
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				// 判断容器中是否已存在该beanDefinition
				if (checkCandidate(beanName, candidate)) {
				    // 封装成BeanDefinitionHolder 
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					// 根据@Scope中的proxyMode值判断是否需要生成代理
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					// 注册到beanDefinitionMap
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}

findCandidateComponents:

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
    // 如果存在索引,并且索引的类都可以成为bean。使用带有索引的方式生成BeanDefinition。(用的较少,源码else里面的很类似,可能性能相对高一点,这里不详细分析)
    if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
        return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
    }
    else {
        // 扫描包含Component注解的可成为Bean的方法:大部分情况下走的扫描方法
        return scanCandidateComponents(basePackage);
    }
}
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
		    // 获取扫描class的路径规则,格式:classpath*:com/demo/simLogin/**/*.class
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			// 获取符合规则的所有class的Resource
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			// 遍历资源
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				// 是否可读
				if (resource.isReadable()) {
					try {
					    // 得到当前资源的元数据
						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
						// 根据excludeFilters、includeFilters以及@Conditional判断
						if (isCandidateComponent(metadataReader)) {
						    // 生成BeanDefinition
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							// 将当前资源保存
							sbd.setResource(resource);
							sbd.setSource(resource);
							// 过滤掉接口,过滤掉内部类,过滤掉没有@Lookup方法的抽象类
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								// 加入方法结果集中
								candidates.add(sbd);
							}
							else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						}
						else {
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吖土豆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值