前言
在我们刚开始接触Spring的时,要定义bean的话需要在xml中编写,比如
<bean id="myBean" class="your.pkg.YourClass"/>
但当 bean 多的时候则非常麻烦,于是出了一个 component-scan 来指定扫描的包,它会去扫描这个包下的所有 class
<context:component-scan base-package="your.pkg"/>
后来注解流行起来,出现了 @ComponentScan 注解,作用跟 component-scan 一样
@ComponentScan(basePackages = {"your.pkg", "other.pkg"})public class Application { ... }
但无论是哪一种方式,它们只能扫描 Spring 定义的注解,例如 @Component、@Service 等,若要扫描自定义注解,就要自定义扫描器
Spring 内置的扫描器
component-scan 标签底层使用 ClassPathBeanDefinitionScanner 该类来完成扫描工作。
@ComponentScan 注解配合 @Configuration 注解使用,底层使用 ComponentScanAnnotationParser 解析器完成解析工作
ComponentScanAnnotationParser 解析器内部使用 ClassPathBeanDefinitionScanner 扫描器,其内部处理过程如下:
遍历 basePackages 找出包下的所有的 class,封装成 Resource 接口集合,这个 Resource 接口是 Spring 对资源的封装,有 FileSystemResource、ClassPathResource、UrlResource 实现等
遍历 Resource 集合,通过 includeFilters 和 excludeFilters 判断是否解析。这里的 includeFilters 和 excludeFilters 是 TypeFilter 接口类型的集合。TypeFilter 接口是一个用于判断类型是否满足要求的类型过滤器
excludeFilters 中只要有一个 TypeFilter 满足条件,这个 Resource 就会被过滤。includeFilters 中只要有一个 TypeFilter 满足条件,这个 Resource 就不会被过滤
把所匹配的 Resource 封装成 ScannedGenericBeanDefinition 添加到 BeanDefinition 结果集中并返回
ClassPathBeanDefinitionScanner 继承 ClassPathScanningCandidateComponentProvider
,它的构造函数提供了一个 useDefaultFilters 参数,若为 true 则会添加默认的 TypeFilter
public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters) { this(useDefaultFilters, new StandardEnvironment()); }
TypeFilter 接口
public interface TypeFilter { boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException; }
TypeFilter 接口有一些实现类,例如:
AnnotationTypeFilter :类是否有注解修饰
RegexPatternTypeFilter:类名是否满足正则表达式
自定义首描
通常情况下,要完成扫包功能,可以直接使用 ClassPathScanningCandidateComponentProvider 完成,并加上 TypeFilter 即可,例如扫描某个包下带有 @Test 注解的类
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); // 不使用默认的TypeFilterprovider.addIncludeFilter(new AnnotationTypeFilter(Test.class));Set<BeanDefinition> beanDefinitionSet = provider.findCandidateComponents("spring.demo.entity");
若需要更复杂的功能,可继承 ClassPathScanningCandidateComponentProvider 实现自定义扫描器
作者:林塬
链接:https://www.jianshu.com/p/d32c26368fa6
共同学习,写下你的评论
评论加载中...
作者其他优质文章