ClassPathBeanDefinitionScanner学习

简介

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() + "]");
   }

}
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值