继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

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

撒科打诨
关注TA
已关注
手记 265
粉丝 45
获赞 144

前言

  • 在我们刚开始接触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


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP