为了账号安全,请及时绑定邮箱和手机立即绑定

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

标签:
Spring

前言

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


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
移动开发工程师
手记
粉丝
45
获赞与收藏
144

关注作者,订阅最新文章

阅读免费教程

  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消