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

2022-08-06 12:46:54

扫描bean

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

protectedSet<BeanDefinitionHolder>doScan(String... basePackages){Assert.notEmpty(basePackages,"At least one base package must be specified");Set<BeanDefinitionHolder> beanDefinitions=newLinkedHashSet<>();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(candidateinstanceofAbstractBeanDefinition){postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);}if(candidateinstanceofAnnotatedBeanDefinition){AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}if(checkCandidate(beanName, candidate)){BeanDefinitionHolder definitionHolder=newBeanDefinitionHolder(candidate, beanName);
   				definitionHolder=AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder,this.registry);
   				beanDefinitions.add(definitionHolder);registerBeanDefinition(definitionHolder,this.registry);}}}return beanDefinitions;}

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

ClassPathScanningCandidateComponentProvider#scanCandidateComponents(String basePackage)

privateSet<BeanDefinition>scanCandidateComponents(String basePackage){Set<BeanDefinition> candidates=newLinkedHashSet<>();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=newScannedGenericBeanDefinition(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) 确定给定的bean定义是否符合候选条件。默认实现检查该类是否不是接口,并且不依赖于封闭的类。该方法可以在子类中覆盖。若满足则添加到候选者集合中

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

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

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

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

protectedbooleanisCandidateComponent(MetadataReader metadataReader)throwsIOException{for(TypeFilter tf:this.excludeFilters){if(tf.match(metadataReader,getMetadataReaderFactory())){returnfalse;}}for(TypeFilter tf:this.includeFilters){if(tf.match(metadataReader,getMetadataReaderFactory())){returnisConditionMatch(metadataReader);}}returnfalse;}

spirngboot扫描时的includeFilters

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

mybatis扫描时的includeFilters和excludeFilters

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

构造ClassPathMapperScanne添加的 includeFilters和excludeFilters

if(acceptAllInterfaces){// default include filter that accepts all classesaddIncludeFilter((metadataReader, metadataReaderFactory)->true);}// exclude package-info.javaaddExcludeFilter((metadataReader, metadataReaderFactory)->{String className= metadataReader.getClassMetadata().getClassName();return className.endsWith("package-info");});
  • 作者:sinat_33472737
  • 原文链接:https://blog.csdn.net/sinat_33472737/article/details/124632134
    更新时间:2022-08-06 12:46:54