Spring:自定义类扫描器(扫包)

相关文章:Spring:获取容器中的Bean
相关文章:Spring Boot:容器加载时执行特定操作

前言

  • 在我们刚开始接触Spring的时,要定义bean的话需要在xml中编写,比如

  • 但当 bean 多的时候则非常麻烦,于是出了一个 component-scan 来指定扫描的包,它会去扫描这个包下的所有 class

  • 后来注解流行起来,出现了 @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); // 不使用默认的TypeFilter
provider.addIncludeFilter(new AnnotationTypeFilter(Test.class));
Set beanDefinitionSet = provider.findCandidateComponents("spring.demo.entity");
  • 若需要更复杂的功能,可继承 ClassPathScanningCandidateComponentProvider 实现自定义扫描器

你可能感兴趣的:(Spring:自定义类扫描器(扫包))