spring扫描bean以及mybatis扫描mapper对应的bean

扫描bean

ClassPathBeanDefinitionScanner#doScan(String… basePackages):在指定的基本程序包中执行扫描,返回已注册的bean定义。

	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) {
   			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
   			candidate.setScope(scopeMetadata.getScopeName());
   			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
   			if (candidate instanceof AbstractBeanDefinition) {
   				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
   			}
   			if (candidate instanceof AnnotatedBeanDefinition) {
   				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
   			}
   			if (checkCandidate(beanName, candidate)) {
   				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
   				definitionHolder =
   						AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
   				beanDefinitions.add(definitionHolder);
   				registerBeanDefinition(definitionHolder, this.registry);
   			}
   		}
   	}
   	return beanDefinitions;
   }

findCandidateComponents(basePackage):扫描类路径以查找候选组件。具体扫描为父类的如下方法:

ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage)

	private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			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);
						if (isCandidateComponent(metadataReader)) {
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							sbd.setResource(resource);
							sbd.setSource(resource);
							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);
								}
							}
						}
  1. 获取basePackage下的所有资源。通过Ant样式的PathMatcher查找与给定位置模式匹配的所有资源。 支持jar文件和zip文件以及文件系统中的资源。
  2. 遍历所有的resources,将resource包装成SimpleMetadataReader,SimpleMetadataReader包含读取resource注解元数据的AnnotationMetadataReadingVisitor:ASM类访问者,用于查找类名称和实现的类型以及在类上定义的注解,并通过AnnotationMetadata接口将其公开。
  3. 判断metadataReader是否满足条件: isCandidateComponent(MetadataReader metadataReader) 确定给定的类是否不匹配任何排除过滤器并且是否匹配至少一个包含过滤器。
  4. 若第3步满足则生成一个ScannedGenericBeanDefinition类型的BeanDefinition,接着判断该BeanDefinition是否满足条件:isCandidateComponent(AnnotatedBeanDefinition beanDefinition) 确定给定的b​​ean定义是否符合候选条件。默认实现检查该类是否不是接口,并且不依赖于封闭的类。该方法可以在子类中覆盖。若满足则添加到候选者集合中

注意:上述两个isCandidateComponent方法都是可以子类重写的,mybatis就重写了第二个isCandidateComponent(AnnotatedBeanDefinition beanDefinition)

//mybatis的ClassPathMapperScanner重写的
  @Override
  protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
    return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
  }

包含过滤器includeFilters和排除过滤器excludeFilters

includeFilters和excludeFilters是在构造ClassPathBeanDefinitionScanner时声明的

	protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
		for (TypeFilter tf : this.excludeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return false;
			}
		}
		for (TypeFilter tf : this.includeFilters) {
			if (tf.match(metadataReader, getMetadataReaderFactory())) {
				return isConditionMatch(metadataReader);
			}
		}
		return false;
	}

spirngboot扫描时的includeFilters

包含@Component和@ManagedBean
在这里插入图片描述

mybatis扫描时的includeFilters和excludeFilters

mybatis使用ClassPathMapperScanner扫描,ClassPathMapperScanner 继承了ClassPathBeanDefinitionScanner

构造ClassPathMapperScanne添加的 includeFilters和excludeFilters

    if (acceptAllInterfaces) {
      // default include filter that accepts all classes
      addIncludeFilter((metadataReader, metadataReaderFactory) -> true);
    }

    // exclude package-info.java
    addExcludeFilter((metadataReader, metadataReaderFactory) -> {
      String className = metadataReader.getClassMetadata().getClassName();
      return className.endsWith("package-info");
    });
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值