欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring注解 @ComponentScan,@ComponentScans 以及@Filter的使用

程序员文章站 2022-06-17 10:26:47
...

先说下就个注解的作用:

@ComponentScan: 指定包路径扫描,把@Controller、@Service、@Repository,@Component标注的类,实例化到spring容器中

@Filter: 是@ComponentScan注解类中的子注解(内部注解),可以指定一些过滤规则

                    FilterType.ANNOTATION:按照注解注入

                   FilterType.ASSIGNABLE_TYPE:按照给定的类型注入

                   FilterType.ASPECTJ:使用ASPECTJ表达式

                   FilterType.REGEX:使用正则指定

                    FilterType.CUSTOM:使用自定义规则

@ComponentScans:是@ComponentScan注解的集合,里面可以指定多个@ComponentScan注解,扫描多个包路径

对应spring 的xml配置如下

<context:component-scan base-package="com.badger"></context:component-scan>

创建一个工程,引入spring的基础包

<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.12.RELEASE</version>
        </dependency>
​

在org.springframework.context.annotation包下,查看ComponentScan的注解定义信息,这个注解,标注了@Repeatable(ComponentScans.class),在jdk1.8以上,可以重复标注,都会生效,也可以使用ComponentScans.class,使用@ComponentScan注解的数组,标注多个扫描

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    //字符串形式指定扫描的包路径
    @AliasFor("basePackages")
    String[] value() default {};
//字符串形式指定扫描的包路径
    @AliasFor("value")
    String[] basePackages() default {};
//这个英文翻译,大概就是指定类或者接口的类型,会按照指定的类所在的包,扫描包下的类
    Class<?>[] basePackageClasses() default {};
​
    //为bean生成名称的规则的类,需要实现BeanNameGenerator接口,后面指定了默认的生成规则
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
​
    //用于解析bean定义范围的策略接口。(单例,多例等
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
    //各种作用域代理选项 
    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
    //看解释,以及默认值(static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";),是扫描的文件类型
    String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
​
    //是否启动自动扫描所有标注了 @Controller、@Service、@Repository,@Component的类
    boolean useDefaultFilters() default true;
    //扫描只包含Filter规则的类
    Filter[] includeFilters() default {};
 //排除规则Filter的类
    Filter[] excludeFilters() default {};
//懒加载
    boolean lazyInit() default false;
​
    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    @interface Filter {
        //Filter的定义策略
        FilterType type() default FilterType.ANNOTATION;
        //跟type()配合使用
        @AliasFor("classes")
        Class<?>[] value() default {};
 //跟type()配合使用
        @AliasFor("value")
        Class<?>[] classes() default {};
        /**  
            跟type()配合使用,大概就是,如果指定的类型是ASPECTJ,那么就是ASPECTJ的表达式,是REGEX,就是REGEX的表达式,不常用
         * The pattern (or patterns) to use for the filter, as an alternative
         * to specifying a Class {@link #value}.
         * <p>If {@link #type} is set to {@link FilterType#ASPECTJ ASPECTJ},
         * this is an AspectJ type pattern expression. If {@link #type} is
         * set to {@link FilterType#REGEX REGEX}, this is a regex pattern
         * for the fully-qualified class names to match.
         * @see #type
         * @see #classes
         */
        String[] pattern() default {};
    }
}

 

下面直接上代码,看使用的方式

//配置类==配置文件
@Configuration // 告诉Spring这是一个配置类
@ComponentScan(value = "com.bader", includeFilters = {
        //只扫描有@Controller注解的类
        @Filter(type = FilterType.ANNOTATION, classes = { Controller.class }),
        //只扫描类型是BookService的类
        @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { BookService.class }),
       //自定义过滤规则
        @Filter(type = FilterType.CUSTOM, classes = { MyTypeFilter.class }) }, 
        useDefaultFilters = false)
// @ComponentScan value:指定要扫描的包
// excludeFilters = Filter[] :指定扫描的时候按照什么规则排除那些组件
// includeFilters = Filter[] :指定扫描的时候只需要包含哪些组件
// FilterType.ANNOTATION:按照注解
// FilterType.ASSIGNABLE_TYPE:按照给定的类型;
// FilterType.ASPECTJ:使用ASPECTJ表达式
// FilterType.REGEX:使用正则指定
// FilterType.CUSTOM:使用自定义规则
public class MyConfig {
​
}

自定义的Filter,最后的CUSTOM,也说了,需要实现org.springframework.core.type.filter.TypeFilter接口

spring注解 @ComponentScan,@ComponentScans 以及@Filter的使用

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);
        //根据扫描的className,包含service的,扫描成功
        if (className.contains("service")) {
            return true;
        }
        return false;
    }
}

具体的使用,差不多都在这里了,关于测试,大概自己去测试吧