一、前言
本文用到的是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
流程如下:
- 调用
findCandidateComponents()
找到所有的BeanDefinition候选者Set - 遍历所有的BeanDefinition候选者
- 获取@Scope注解的信息并给BeanDefinition设置Scope属性
- 获取Bean的名字
- 添加些默认的Bean定义信息
- 解析@Lazy、@Primary、@DependsOn、@Role、@Description注解的信息
- 封装成BeanDefinitionHolder
- 根据Scope中的proxyMode判断是否需要创建代理
- 注册到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;
}