开发者社区> 优惠码发放> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

【Spring注解驱动开发】自定义TypeFilter指定@ComponentScan注解的过滤规则

简介:
+关注继续查看

【Spring注解驱动开发】自定义TypeFilter指定@ComponentScan注解的过滤规则

写在前面
Spring的强大之处不仅仅是提供了IOC容器,能够通过过滤规则指定排除和只包含哪些组件,它还能够通过自定义TypeFilter来指定过滤规则。如果Spring内置的过滤规则不能够满足我们的需求,那么我们就可以通过自定义TypeFilter来实现我们自己的过滤规则。

项目工程源码已经提交到GitHub:https://github.com/sunshinelyz/spring-annotation

FilterType中常用的规则
在使用@ComponentScan注解实现包扫描时,我们可以使用@Filter指定过滤规则,在@Filter中,通过type指定过滤的类型。而@Filter注解的type属性是一个FilterType枚举,如下所示。

package org.springframework.context.annotation;

public enum FilterType {

ANNOTATION,
ASSIGNABLE_TYPE,
ASPECTJ,
REGEX,
CUSTOM

}
每个枚举值的含义如下所示。

(1)ANNOTATION:按照注解进行过滤。

例如,使用@ComponentScan注解进行包扫描时,按照注解只包含标注了@Controller注解的组件,如下所示。

@ComponentScan(value = "io.mykit.spring", includeFilters = {

@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})

}, useDefaultFilters = false)
(2)ASSIGNABLE_TYPE:按照给定的类型进行过滤。

例如,使用@ComponentScan注解进行包扫描时,按照给定的类型只包含PersonService类(接口)或其子类(实现类或子接口)的组件,如下所示。

@ComponentScan(value = "io.mykit.spring", includeFilters = {

@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {PersonService.class})

}, useDefaultFilters = false)
此时,只要是PersonService类型的组件,都会被加载到容器中。也就是说:当PersonService是一个Java类时,Person类及其子类都会被加载到Spring容器中;当PersonService是一个接口时,其子接口或实现类都会被加载到Spring容器中。

(3)ASPECTJ:按照ASPECTJ表达式进行过滤

例如,使用@ComponentScan注解进行包扫描时,按照ASPECTJ表达式进行过滤,如下所示。

@ComponentScan(value = "io.mykit.spring", includeFilters = {

@Filter(type = FilterType.ASPECTJ, classes = {AspectJTypeFilter.class})

}, useDefaultFilters = false)
(4)REGEX:按照正则表达式进行过滤

例如,使用@ComponentScan注解进行包扫描时,按照正则表达式进行过滤,如下所示。

@ComponentScan(value = "io.mykit.spring", includeFilters = {

@Filter(type = FilterType.REGEX, classes = {RegexPatternTypeFilter.class})

}, useDefaultFilters = false)
(5)CUSTOM:按照自定义规则进行过滤。

如果实现自定义规则进行过滤时,自定义规则的类必须是org.springframework.core.type.filter.TypeFilter接口的实现类。

例如,按照自定义规则进行过滤,首先,我们需要创建一个org.springframework.core.type.filter.TypeFilter接口的实现类MyTypeFilter,如下所示。

public class MyTypeFilter implements TypeFilter {

@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
    return false;
}

}
当我们实现TypeFilter接口时,需要实现TypeFilter接口中的match()方法,match()方法的返回值为boolean类型。当返回true时,表示符合规则,会包含在Spring容器中;当返回false时,表示不符合规则,不会包含在Spring容器中。另外,在match()方法中存在两个参数,分别为MetadataReader类型的参数和MetadataReaderFactory类型的参数,含义分别如下所示。

metadataReader:读取到的当前正在扫描的类的信息。
metadataReaderFactory:可以获取到其他任务类的信息。
接下来,使用@ComponentScan注解进行如下配置。

@ComponentScan(value = "io.mykit.spring", includeFilters = {

@Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})

}, useDefaultFilters = false)
在FilterType枚举中,ANNOTATION和ASSIGNABLE_TYPE是比较常用的,ASPECTJ和REGEX不太常用,如果FilterType枚举中的类型无法满足我们的需求时,我们也可以通过实现org.springframework.core.type.filter.TypeFilter接口来自定义过滤规则,此时,将@Filter中的type属性设置为FilterType.CUSTOM,classes属性设置为自定义规则的类对应的Class对象。

实现自定义过滤规则
在项目的io.mykit.spring.plugins.register.filter包下新建MyTypeFilter,并实现org.springframework.core.type.filter.TypeFilter接口。此时,我们先在MyTypeFilter类中打印出当前正在扫描的类名,如下所示。

package io.mykit.spring.plugins.register.filter;

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;

/**

  • @author binghe
  • @version 1.0.0
  • @description 自定义过滤规则
    */

public class MyTypeFilter implements TypeFilter {

/**
 * metadataReader:读取到的当前正在扫描的类的信息
 * metadataReaderFactory:可以获取到其他任务类的信息
 */
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
    //获取当前类注解的信息
    AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
    //获取当前正在扫描的类的信息
    ClassMetadata classMetadata = metadataReader.getClassMetadata();
    //获取当前类的资源信息,例如:类的路径等信息
    Resource resource = metadataReader.getResource();
    //获取当前正在扫描的类名
    String className = classMetadata.getClassName();
    //打印当前正在扫描的类名
    System.out.println("-----> " + className);
    return false;
}

}
接下来,我们在PersonConfig类中配置自定义过滤规则,如下所示。

@Configuration
@ComponentScans(value = {

    @ComponentScan(value = "io.mykit.spring", includeFilters = {
            @Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
    }, useDefaultFilters = false)

})
public class PersonConfig {

@Bean("person")
public Person person01(){
    return new Person("binghe001", 18);
}

}
接下来,我们运行SpringBeanTest类中的testComponentScanByAnnotation()方法进行测试,输出的结果信息如下所示。

-----> io.mykit.spring.test.SpringBeanTest
-----> io.mykit.spring.bean.Person
-----> io.mykit.spring.plugins.register.controller.PersonController
-----> io.mykit.spring.plugins.register.dao.PersonDao
-----> io.mykit.spring.plugins.register.filter.MyTypeFilter
-----> io.mykit.spring.plugins.register.service.PersonService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig
person
可以看到,已经输出了当前正在扫描的类的名称,同时,除了Spring内置的bean名称外,只输出了personConfig和person,没有输出使用@Repository、@Service、@Controller注解标注的组件名称。这是因为当前PersonConfig上标注的@ComponentScan注解是使用自定义的规则,而在MyTypeFilter自定义规则的实现类中,直接返回了false值,将所有的bean都排除了。

我们可以在MyTypeFilter类中简单的实现一个规则,例如,当前扫描的类名称中包含有字符串Person,就返回true,否则返回false。此时,MyTypeFilter类中match()方法的实现如下所示。

@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
    //获取当前类注解的信息
    AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
    //获取当前正在扫描的类的信息
    ClassMetadata classMetadata = metadataReader.getClassMetadata();
    //获取当前类的资源信息,例如:类的路径等信息
    Resource resource = metadataReader.getResource();
    //获取当前正在扫描的类名
    String className = classMetadata.getClassName();
    //打印当前正在扫描的类名
    System.out.println("-----> " + className);
    return className.contains("Person");
}

此时,在io.mykit.spring包下的所有类都会通过MyTypeFilter类的match()方法,来验证类名是否包含Person,如果包含则返回true,否则返回false。

我们再次运行SpringBeanTest类中的testComponentScanByAnnotation()方法进行测试,输出的结果信息如下所示。

-----> io.mykit.spring.test.SpringBeanTest
-----> io.mykit.spring.bean.Person
-----> io.mykit.spring.plugins.register.controller.PersonController
-----> io.mykit.spring.plugins.register.dao.PersonDao
-----> io.mykit.spring.plugins.register.filter.MyTypeFilter
-----> io.mykit.spring.plugins.register.service.PersonService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig
person
personController
personDao
personService
此时,结果信息中输出了使用@Repository、@Service、@Controller注解标注的组件名称,分别为:personDao、personService和personController。

好了,咱们今天就聊到这儿吧!别忘了给个在看和转发,让更多的人看到,一起学习一起进步!!

项目工程源码已经提交到GitHub:https://github.com/sunshinelyz/spring-annotation

写在最后
如果觉得文章对你有点帮助,请微信搜索并关注「 冰河技术 」微信公众号,跟冰河学习Spring注解驱动开发。公众号回复“spring注解”关键字,领取Spring注解驱动开发核心知识图,让Spring注解驱动开发不再迷茫。

原文地址https://www.cnblogs.com/binghe001/p/13063046.html

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Spring——2、使用@ComponentScan自动扫描组件并指定扫描规则
在实际项目中,我们更多的是使用Spring的包扫描功能对项目中的包进行扫描,凡是在指定的包或其子包中的类上标注了@Repository、@Service、@Controller、@Component注解的类都会被扫描到,并将这个类注入到Spring容器中。 Spring包扫描功能可以使用XML配置文件进行配置,也可以直接使用@ComponentScan注解进行设置,使用@ComponentScan注解进行设置比使用XML配置文件来配置要简单的多。
0 0
【小家Spring】Spring MVC容器的web九大组件之---HandlerAdapter源码详解---HttpMessageConverter的匹配规则(选择原理)(下)
【小家Spring】Spring MVC容器的web九大组件之---HandlerAdapter源码详解---HttpMessageConverter的匹配规则(选择原理)(下)
0 0
【小家Spring】Spring MVC容器的web九大组件之---HandlerAdapter源码详解---HttpMessageConverter的匹配规则(选择原理)(中)
【小家Spring】Spring MVC容器的web九大组件之---HandlerAdapter源码详解---HttpMessageConverter的匹配规则(选择原理)(中)
0 0
【小家Spring】Spring MVC容器的web九大组件之---HandlerAdapter源码详解---HttpMessageConverter的匹配规则(选择原理)(上)
【小家Spring】Spring MVC容器的web九大组件之---HandlerAdapter源码详解---HttpMessageConverter的匹配规则(选择原理)(上)
0 0
Spring Cloud Alibaba Sentinel 整合 nacos 进行规则持久化
Spring Cloud Alibaba Sentinel 整合 nacos 进行规则持久化
0 0
Spring Cloud Alibaba基础教程:Nacos配置的加载规则详解
Spring Cloud Alibaba基础教程:Nacos配置的加载规则详解
0 0
Spring Cloud Alibaba基础教程:Sentinel使用Apollo存储规则
Spring Cloud Alibaba基础教程:Sentinel使用Apollo存储规则
0 0
Spring Cloud Alibaba基础教程:Sentinel Dashboard中修改规则同步到Apollo
Spring Cloud Alibaba基础教程:Sentinel Dashboard中修改规则同步到Apollo
0 0
Spring Cloud Alibaba基础教程:Sentinel Dashboard中修改规则同步到Nacos
Spring Cloud Alibaba基础教程:Sentinel Dashboard中修改规则同步到Nacos
0 0
【Spring注解驱动开发】自定义TypeFilter指定@ComponentScan注解的过滤规则
Spring的强大之处不仅仅是提供了IOC容器,能够通过过滤规则指定排除和只包含哪些组件,它还能够通过自定义TypeFilter来指定过滤规则。如果Spring内置的过滤规则不能够满足我们的需求,那么我们就可以通过自定义TypeFilter来实现我们自己的过滤规则。
0 0
+关注
优惠码发放
阿里云优惠码阿里云推荐券bieryun.com
文章
问答
文章排行榜
最热
最新
相关电子书
更多
Java Spring Boot开发实战系列课程【第7讲】:Spring Boot 2.0安全机制与MVC身份验证实战(Java面试题)
立即下载
Java Spring Boot开发实战系列课程【第15讲】:Spring Boot 2.0 API与Spring REST Docs实战
立即下载
Java Spring Boot开发实战系列课程【第6讲】:Spring Boot 2.0实战MyBatis与优化(Java面试题)
立即下载