• 【Spring】——3、自定义TypeFilter指定@ComponentScan注解的过滤规则


    在这里插入图片描述

    📫作者简介:zhz小白
    公众号:小白的Java进阶之路
    专业技能:
    1、Java基础,并精通多线程的开发,熟悉JVM原理
    2、熟悉Java基础,并精通多线程的开发,熟悉JVM原理,具备⼀定的线上调优经验
    3、熟悉MySQL数据库调优,索引原理等,⽇志原理等,并且有出过⼀篇专栏
    4、了解计算机⽹络,对TCP协议,滑动窗⼝原理等有⼀定了解
    5、熟悉Spring,Spring MVC,Mybatis,阅读过部分Spring源码
    6、熟悉SpringCloud Alibaba体系,阅读过Nacos,Sentinel,Seata,Dubbo,Feign,Gateway核⼼源码与设计,⼆次开发能⼒
    7、熟悉消息队列(Kafka,RocketMQ)的原理与设计
    8、熟悉分库分表ShardingSphere,具有真实⽣产的数据迁移经验
    9、熟悉分布式缓存中间件Redis,对其的核⼼数据结构,部署架构,⾼并发问题解决⽅案有⼀定的积累
    10、熟悉常⽤设计模式,并运⽤于实践⼯作中
    11、了解ElasticSearch,对其核⼼的原理有⼀定的了解
    12、了解K8s,Jekins,GitLab
    13、了解VUE,GO
    14、⽬前有正在利⽤闲暇时间做互游游戏,开发、运维、运营、推销等

    本人著作git项目:https://gitee.com/zhouzhz/star-jersey-platform,有兴趣的可以私聊博主一起编写,或者给颗star
    领域:对支付(FMS,FUND,PAY),订单(OMS),出行行业等有相关的开发领域
    🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~

    FilterType中常用的规则

    在使用@ComponentScan注解实现包扫描时,我们可以使用@Filter指定过滤规则,在@Filter中,通过type来指定过滤的类型。而@Filter注解中的type属性是一个FilterType枚举,其源码为:

    public enum FilterType {
    
    	ANNOTATION,
    
    	ASSIGNABLE_TYPE,
    
    	ASPECTJ,
    
    	REGEX,
    
    	CUSTOM
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    FilterType.ANNOTATION:按照注解进行包含或者排除(常用)

    使用@ComponentScan注解进行包扫描时,如果要想按照注解只包含标注了@Controller注解的组件。

    @ComponentScan(value="com.zhz", includeFilters={
    		/*
    		 * type:指定你要排除的规则,是按照注解进行排除,还是按照给定的类型进行排除,还是按照正则表达式进行排除,等等
    		 * classes:我们需要Spring在扫描时,只包含@Controller注解标注的类
    		 */
    		@Filter(type=FilterType.ANNOTATION, classes={Controller.class})
    }, useDefaultFilters=false) // value指定要扫描的包
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    FilterType.ASSIGNABLE_TYPE:按照给定的类型进行包含或者排除(常用)

    使用@ComponentScan注解进行包扫描时,如果要想按照给定的类型只包含BookService类(接口)或其子类(实现类或子接口)的组件。

    @ComponentScan(value="com.zhz", includeFilters={
    		/*
    		 * type:指定你要排除的规则,是按照注解进行排除,还是按照给定的类型进行排除,还是按照正则表达式进行排除,等等
    		 */
    		// 只要是BookService这种类型的组件都会被加载到容器中,不管是它的子类还是什么它的实现类。记住,只要是BookService这种类型的
    		@Filter(type=FilterType.ASSIGNABLE_TYPE, classes={BookService.class})
    }, useDefaultFilters=false) // value指定要扫描的包
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    只要是BookService这种类型的组件,都会被加载到容器中。也就是说,当BookService是一个Java类时,该类及其子类都会被加载到Spring容器中;当BookService是一个接口时,其子接口或实现类都会被加载到Spring容器中。

    FilterType.ASPECTJ:按照ASPECTJ表达式进行包含或者排除(很少用)

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

    @ComponentScan(value="com.zhz", includeFilters={
    		/*
    		 * type:指定你要排除的规则,是按照注解进行排除,还是按照给定的类型进行排除,还是按照正则表达式进行排除,等等
    		 */
    		@Filter(type=FilterType.ASPECTJ, classes={AspectJTypeFilter.class})
    }, useDefaultFilters=false) // value指定要扫描的包
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    FilterType.REGEX:按照正则表达式进行包含或者排除(很少用)

    使用@ComponentScan注解进行包扫描时,按照正则表达式进行过滤

    @ComponentScan(value="com.meimeixia", includeFilters={
    		/*
    		 * type:指定你要排除的规则,是按照注解进行排除,还是按照给定的类型进行排除,还是按照正则表达式进行排除,等等
    		 */
    		@Filter(type=FilterType.REGEX, classes={RegexPatternTypeFilter.class})
    }, useDefaultFilters=false) // value指定要扫描的包
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    FilterType.CUSTOM:按照自定义规则进行包含或者排除

    • 如果实现自定义规则进行过滤时,自定义规则的类必须是org.springframework.core.type.filter.TypeFilter接口的实现类
    • 按照自定义规则进行过滤,首先我们得创建org.springframework.core.type.filter.TypeFilter接口的一个实现类,例如MyTypeFilter
    package com.zhz.filter;
    
    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 zhouhengzhe
     * @description: 自定义规则
     * @date 2022/11/4 22:49
     * @since v1
     */
    public class MyTypeFilter implements TypeFilter {
    
        /**
         * 参数:
         * metadataReader:读取到的当前正在扫描的类的信息
         * metadataReaderFactory:可以获取到其他任何类的信息的(工厂)
         */
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
    
            // 这儿我们先让其返回false
            return false;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 当我们实现TypeFilter接口时,需要实现该接口中的match()方法,match()方法的返回值为boolean类型。
    • 当返回true时,表示符合规则,会包含在Spring容器中;当返回false时,表示不符合规则,那就是一个都不匹配,自然就都不会被包含在Spring容器中。
    • 在match()方法中存在两个参数,分别为MetadataReader类型的参数和MetadataReaderFactory类型的参数
      • metadataReader:读取到的当前正在扫描的类的信息
      • metadataReaderFactory:可以获取到其他任何类的信息的工厂

    使用@ComponentScan注解进行如下配置

    @ComponentScan(value="com.meimeixia", includeFilters={
    		/*
    		 * type:指定你要排除的规则,是按照注解进行排除,还是按照给定的类型进行排除,还是按照正则表达式进行排除,等等
    		 */
    		// 指定新的过滤规则,这个过滤规则是我们自个自定义的,过滤规则就是由我们这个自定义的MyTypeFilter类返回true或者false来代表匹配还是没匹配
    		@Filter(type=FilterType.CUSTOM, classes={MyTypeFilter.class})
    }, useDefaultFilters=false) // value指定要扫描的包
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    如果FilterType枚举中的类型无法满足我们的需求时,我们也可以通过实现org.springframework.core.type.filter.TypeFilter接口来自定义过滤规则,此时,将@Filter中的type属性设置为FilterType.CUSTOM,classes属性设置为自定义规则的类所对应的Class对象。

    实现自定义过滤规则

    从上面可以知道,我们在项目的com.meimeixia.config包下新建了一个类,即MyTypeFilter,它实现了org.springframework.core.type.filter.TypeFilter接口。此时,我们先在MyTypeFilter类中打印出当前正在扫描的类名:

    package com.zhz.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 zhouhengzhe
     * @description: 自定义规则
     * @date 2022/11/4 22:49
     * @since v1
     */
    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);
    
            // 这儿我们先让其返回false
            return false;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    我们在MainConfig类中配置自定义过滤规则:

    package com.zhz.config;
    
    import com.zhz.bean.Person;
    import com.zhz.filter.MyTypeFilter;
    import org.springframework.context.annotation.*;
    import org.springframework.stereotype.Controller;
    import org.springframework.stereotype.Service;
    
    /**
     * @author zhouhengzhe
     * @description: todo
     * @date 2022/11/4 10:27
     * @since v1
     */
    
    @ComponentScan(value = {"com.zhz"}, includeFilters = {
            /*
             * type:指定你要排除的规则,是按照注解进行排除,还是按照给定的类型进行排除,还是按照正则表达式进行排除,等等
             * classes:除了@Controller标注的组件之外,IOC容器中剩下的组件我都要,即相当于是我要排除@Controller和@Service这俩注解标注的组件。
             */
            @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})}, useDefaultFilters = false)
    @Configuration
    public class MainConfig {
    
        /**
         * @Bean注解是给IOC容器中注册一个bean,类型自然就是返回值的类型,id默认是用方法名作为id
         */
        @Bean(name = "person")
        public Person person1() {
            return new Person("zhz", 20);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    测试类如下:

    package com.zhz.test;
    
    import com.zhz.config.MainConfig;
    import org.junit.Test;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * @author zhouhengzhe
     * @description: todo
     * @date 2022/11/4 10:58
     * @since v1
     */
    public class IOCTest {
    
        @SuppressWarnings("resource")
        @Test
        public void test() {
            AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
            // 我们现在就来看一下IOC容器中有哪些bean,即容器中所有bean定义的名字
            String[] definitionNames = applicationContext.getBeanDefinitionNames();
            for (String name : definitionNames) {
                System.out.println(name);
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    演示效果如下:
    在这里插入图片描述

    可以看到,已经输出了当前正在扫描的类的名称,同时,除了Spring内置的bean的名称之外,只输出了mainConfig和person,而没有输出使用@Repository、@Service、@Controller这些注解标注的组件的名称。这是因为当前MainConfig类上标注的@ComponentScan注解是使用的自定义规则,而在自定义规则的实现类(即MyTypeFilter类)中,直接返回了false,那么就是一个都不匹配了,自然所有的bean就都没被包含进去容器中了。

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

    package com.zhz.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 zhouhengzhe
     * @description: 自定义规则
     * @date 2022/11/4 22:49
     * @since v1
     */
    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);
            if (className.contains("er")){
                return true;
            }
            // 这儿我们先让其返回false
            return false;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    在com.zhz包下的所有类都会通过MyTypeFilter类中的match()方法来验证类名中是否包含有"er"字符串,若包含则返回true,否则返回false。
    在这里插入图片描述

    我们可以发现在com.zhz下只要包含er的Bean都扫进去了,当然有一个比较特殊的类,她就是MainConfig,他是一定会被扫进去的,因为他觉定Person类能不能扫进去。所以该包下的每一个类都会进到这个自定义规则里面进行匹配,若匹配成功,则就会被包含在容器中。

  • 相关阅读:
    交替合并字符串
    javaweb
    Dubbo快速入门
    图像识别(五)| 春天花开却不识?打开百度识图,残差和卷积带你识遍路边野花
    代码随想录训练营day48, 打家劫舍系列问题
    Kafka生产者消息异步发送并返回发送信息api编写教程
    C# SolidWorks 二次开发 API-Solidworks文件关系与打开文件的方式
    江西农业大学择校分析(附23招生简章)
    如何实现视频提取伴奏?看完包你学会~
    Blazor和Vue对比学习(进阶.路由导航一):基本使用
  • 原文地址:https://blog.csdn.net/zhouhengzhe/article/details/127896342