简介
ClassPathBeanDefinitionScanner 是 Spring 框架中的一个类,它用于扫描类路径(classpath)上的组件并注册这些组件作为 Spring 容器中的 Bean。这个类通常用于实现基于 Java 配置的组件扫描,以及基于注解的自动配置。
ClassPathBeanDefinitionScanner 提供了一个简单的方法来扫描特定的包(package)以查找带有特定注解的类,并将这些类注册为 Spring 容器中的 Bean。这对于实现自动配置和简化 Spring 应用的配置非常有用。
以下是一些常用的 ClassPathBeanDefinitionScanner 方法:
- scan(String… basePackages): 扫描指定的包路径,并将找到的带有 @Component, @Service, @Repository, @Controller 等注解的类注册为 Bean。
- addIncludeFilter(TypeFilter filter): 添加一个过滤器,用于包含(即注册)符合特定条件的类。
- addExcludeFilter(TypeFilter filter): 添加一个过滤器,用于排除(即不注册)符合特定条件的类。
- findCandidateComponents(String basePackage): 在指定的包路径下查找候选的组件类。
源码
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {
private final BeanDefinitionRegistry registry;
private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();
@Nullable
private String[] autowireCandidatePatterns;
//beanName生成器
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
//@Scope注解解析器
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
private boolean includeAnnotationConfig = true;
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment) {
this(registry, useDefaultFilters, environment,
(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
//是否使用默认的过滤器
if (useDefaultFilters) {
registerDefaultFilters();
}
//设置系统环境
setEnvironment(environment);
//设置资源加载器
setResourceLoader(resourceLoader);
}
/**
* Perform a scan within the specified base packages.
* @param basePackages the packages to check for annotated classes
* @return number of beans registered
* 根据包路径进行扫描
*/
public int scan(String... basePackages) {
//扫描之前的容器中已存在的bean的数量
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
//开始扫描
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
//返回新注册的bean的数量
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//遍历所有包路径
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
//难道当前包下符合条件的所有BeanDefinition
for (BeanDefinition candidate : candidates) {
//设置bean的作用域
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//获取bean的beanName
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
//设置AbstractBeanDefinition中的属性
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//校验当前bean是否重复加入容器中
if (checkCandidate(beanName, candidate)) {
//对bean进行包装
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
//判断当前bean是否需要代理,需要则创建代理对象并返回
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//将bean注册到容器中
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
/**
* 向bean工厂中注册bean
*/
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry);
}
/**
*检查bean是否已经存在了
*/
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
}
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
if (isCompatible(beanDefinition, existingDef)) {
return false;
}
throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}
}