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

作者: 聪明的奇瑞 | 来源:发表于2018-01-25 13:52 被阅读1670次

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

    前言

    • 在我们刚开始接触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); // 不使用默认的TypeFilter
    provider.addIncludeFilter(new AnnotationTypeFilter(Test.class));
    Set<BeanDefinition> beanDefinitionSet = provider.findCandidateComponents("spring.demo.entity");
    
    • 若需要更复杂的功能,可继承 ClassPathScanningCandidateComponentProvider 实现自定义扫描器

    相关文章

      网友评论

        本文标题:Spring:自定义类扫描器(扫包)

        本文链接:https://www.haomeiwen.com/subject/nydvaxtx.html