spring资源扫描

使用Class和Classloader定位资源

在这里插入图片描述

通过Classloader定位资源: 路径不要带/开头,默认就是以classpath为根路径

// 文件路径
ClassLoader classLoader = TestPath.class.getClassLoader();
URL resource = classLoader.getResource("testpath.properties");
System.out.println(resource); 
//  得到结果: file:/G:/5.workspace/3.my-projects/demo/**/target/classes/testpath.properties

 // 目录路径
 URL resource2 = classLoader.getResource("com/txd/util");
System.out.println(resource2);
//  得到结果:file:/G:/5.workspace/3.my-projects/demo/l**/target/classes/com/txd/util

通过Class定位资源:路径带/就是以classpath为根路径(效果同ClassLoader) ; 路径不带/就是相对当前使用的class路径

// 文件路径
URL resource1 = TestPath.class.getResource("/testpath.properties");
System.out.println(resource1); 
// 结果:/ file:/G:/5.workspace/3.my-projects/demo/**/target/classes/testpath.properties
// 目录路径:
URL resource3 = TestPath.class.getResource("test");
System.out.println(resource3);
// 结果:G:/5.workspace/3.my-projects/demo/**/target/classes/com/txd/util/test

spring中的ClassPathBeanDefinitionScanner(基于spring5.1.2)

看spring的源代码发现,主要的方法就是doScan

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) {
        // 从配置的路径下扫描过滤得到所有的bean
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
			    // scope注解
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				// bean的默认配置
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				// 覆盖bean默认配置
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				// 注册到IOC容器
				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;
	}

首先来看第一段:

Set<BeanDefinition> candidates = findCandidateComponents(basePackage);

在这里插入图片描述
从classpath下解析配置路径下的资源。分三种情况:vfs文件,普通文件,jar文件。扫描的类通过ScannedGenericBeanDefinition来保存描述其类信息。

第二段:通过scopeMetadataResolver得到scope注解元数据信息,存到ScannedGenericBeanDefinition中

第三段:添加bean的默认配置

if (candidate instanceof AbstractBeanDefinition) {
	postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}

跟进代码:发现主要是lazyInit默认false,autowireMode默认0(和自动注入:配置0需要手动通过@Autowired注入)
在这里插入图片描述
第四段:通过注解配置覆盖bean的默认配置

if (candidate instanceof AnnotatedBeanDefinition) {
	AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}

跟进代码可用看待几个常用的注解
在这里插入图片描述
第五段:注入ioc

registerBeanDefinition(definitionHolder, this.registry);

mybatis通过重写ClassPathBeanDefinitionScanner的isCandidateComponent(metadataReader)来过滤mapper接口

springboot项目中通过mybatis的自动配置类MybatisAutoConfiguration引入了AutoConfiguredMapperScannerRegistrar

@Configuration
    @Import({MybatisAutoConfiguration.AutoConfiguredMapperScannerRegistrar.class})
    @ConditionalOnMissingBean({MapperFactoryBean.class, MapperScannerConfigurer.class})
    public static class MapperScannerRegistrarNotFoundConfiguration implements InitializingBean {
        public MapperScannerRegistrarNotFoundConfiguration() {
        }

        public void afterPropertiesSet() {
            MybatisAutoConfiguration.logger.debug("Not found configuration for registering mapper bean using @MapperScan, MapperFactoryBean and MapperScannerConfigurer.");
        }
    }

而AutoConfiguredMapperScannerRegistrar又是ImportBeanDefinitionRegistrar的实现,在解析Import的时候执行registerBeanDefinitions注入MapperScannerConfigurer。MapperScannerConfigurer又是BeanDefinitionRegistryPostProcessor的实现,spring初始化会执行postProcessBeanDefinitionRegistry方法,其中使用到了ClassPathMapperScanner。

 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        if (this.processPropertyPlaceHolders) {
            this.processPropertyPlaceHolders();
        }

        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.setAddToConfig(this.addToConfig);
        scanner.setAnnotationClass(this.annotationClass);
        scanner.setMarkerInterface(this.markerInterface);
        scanner.setSqlSessionFactory(this.sqlSessionFactory);
        scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
        scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
        scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
        scanner.setResourceLoader(this.applicationContext);
        scanner.setBeanNameGenerator(this.nameGenerator);
        scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
        if (StringUtils.hasText(this.lazyInitialization)) {
            scanner.setLazyInitialization(Boolean.valueOf(this.lazyInitialization));
        }

        scanner.registerFilters();
        // 扫描mapper接口配置,然后通过isCandidateComponent过滤得到所有接口的bean
        scanner.scan(StringUtils.tokenizeToStringArray(this.basePackage, ",; \t\n"));
    }

重写的isCandidateComponent只要是接口就扫描到spring中成为bean
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值