• Spring 注解之 @ComponentScan


    一、项目的结构如下:

    二、使用 @ComponentScan 注解时,如果不给这个注解的任意属性赋值,那么该注解默认的扫描范围是什么?

    1、在 com.spring01.config 包下创建两个类 SpringConfiguration、Animal.并且在 UserServiceImpl 上加上注解 @Service ,在 UserDaoImpl 上加上注解 @Repository

    // 标记这是一个Spring的配置类
    @Configuration
    @ComponentScan
    public class SpringConfiguration {
    
        // @Bean 注解用于将 Person 类型的对象注入到 Spring 容器中,注入到容器中的对象类型为方法的返回值类型,默认注入的 id 是方法名
        // 如果想指定注入到 Spring 容器中的 id ,可以使用 @Bean("xiaomaomao") ,代表注入到 Spring 容器的 id="xiaomaomao"
        @Bean
        public Person person01() {
            return new Person("Bill Gates", 66);
        }
    	// 这里就代表往 spring 容器中注入了一个 Person 类型的对象, id 为 person02
        @Bean
        public Person person02() {
            return new Person("Linus Torvalds", 44);
        }
    } 
    @Component
    public class Animal {
    }
    @Service
    public class UserServiceImpl implements UserService {
    }
    
    @Repository
    public class UserDaoImpl implements UserDao {
    }  
    

    2、测试类

    public class SpringDemo {
        @Test
        public void springTest01() {
            ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfiguration.class);
    
            // 获取并打印所有的 Bean 的名称
            String[] beanDefinitionNames = context.getBeanDefinitionNames();
            for (String beanDefinitionName : beanDefinitionNames) {
                System.out.println(beanDefinitionName);
            }
        }
    }
    

    3、测试结果

    // Spring框架自身类
    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
    // @ComponentScan 注解扫描,注入到 Spring 容器中,并交由 Spring 容器进行管理
    // SpringConfiguration上标注的是 @Configuration,该注解实际上底层使用的是 @Component 注解,默认的 id 是类名的首字母小写
    springConfiguration
    // Animal 上标注的是 @Component 注解,注入到 Spring 容器的时候默认的 id 是类名首字母小写
    animal
    // @Bean注解,没有显示给值,id 是方法名
    person01
    person02

    结果分析:除了框架自身的类之外,我们实际上注入到 Spring 容器中的对象有 springConfiguration、animal、person01、person02,而使用 @Service 和 @Repository 标注的注解却没有被扫描到并注入到 Spring 容器中,所以说单纯的使用 @ComponentScan 注解标注,而不给该注解的任何属性赋值,那么该注解的扫描范围就是配置类所在的包下面的所有类(配置类是SpringConfiguration ,其所在的包是 com.spring01.config ),而 UserServiceImpl 和 UserDaoImpl 虽然被 @Service 和 @Repository 注解标注,但是它们并不在配置类所在的包下,所以它们没有被扫描到.

    总结: @ComponentScan 默认的扫描范围就是当前类所在的包下的所有注解.

    三、使用 @ComponentScan 注解时,它有哪些属性,这些属性可以赋哪一些值?

    @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 {};
    
    	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
    
    	Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
    	
    	ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
    	
    	String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
    
    	boolean useDefaultFilters() default true;
    
    	Filter[] includeFilters() default {};
    
    	Filter[] excludeFilters() default {};
    
    	boolean lazyInit() default false;
    
    	@Retention(RetentionPolicy.RUNTIME)
    	@Target({})
    	@interface Filter {
    		
    		FilterType type() default FilterType.ANNOTATION;
    		
    		@AliasFor("classes")
    		Class<?>[] value() default {};
    
    		@AliasFor("value")
    		Class<?>[] classes() default {};
    		
    		String[] pattern() default {};
    
    	}
    }
    

    下面我们就挑几个常用的属性来说一说吧

    1、value / basePackages 属性

    @AliasFor("basePackages")
    String[] value() default {};
    
    @AliasFor("value")
    String[] basePackages() default {};
    

     value 和 basePackages 两个属性互为别名,也就是说无论使用它们中的哪一个属性效果都是一样的,它们的作用就是指定 @ComponentScan 这个注解的扫描范围

    一般来说 value 和 basePackages 两个属性我们只会给其中的一个赋值,如果你要同时使用这两个属性,那么请保持这两个属性的值是一样的,否则会出现如下错误:

    // 错误信息
    org.springframework.core.annotation.AnnotationConfigurationException: Different @AliasFor mirror values for annotation 
    [org.springframework.context.annotation.ComponentScan] declared on class com.spring01.config.SpringConfiguration; 
    attribute 'basePackages' and its alias 'value' are declared with values of [{com.spring01.dao}] and [{com.spring01}].
    

    举例: @ComponentScan(value="com.spring01") / @ComponentScan(basePackages="com.spring01")

    它们代表的意思都是扫描 com.spring01 包下的所有注解

    2、excludeFilters 属性

    Filter[] excludeFilters() default {};

    excludeFilters 的属性值是一个 Filter 类型的数组,我们可以看一下这个数组里面的取值

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    @interface Filter {
      // type 属性的默认值是注解类型
      FilterType type() default FilterType.ANNOTATION;
      // value 属性和 classes 属性互为别名,只需要写一个就可以了
      @AliasFor("classes")
      Class<?>[] value() default {};
    	// 与 value 互为别名
      @AliasFor("value")
      Class<?>[] classes() default {};
      // 类型
      String[] pattern() default {};
    }

    type 属性的是一个枚举类,里面的取值如下:
    FilterType.ANNOTATION(默认值)
    FilterType.ASSIGNABLE_TYPE
    FilterType.ASSIGNABLE_TYPE
    FilterType.ASPECTJ
    FilterType.REGEX(正则表达式)
    FilterType.CUSTOM(自定义规则)

    其中最经常使用的值就是 FilterType.ANNOTATION、FilterType.CUSTOM,下面我们来演示一下这两个值有什么用

    一、FilterType.ANNOTATION

    @Configuration
    // 扫描 com.spring01 包下面的所有注解
    @ComponentScan(value = "com.spring01",
            // 如果使用的是 excludeFilters, useDefaultFilters 的默认值就是 true,这里可以省略不写
            useDefaultFilters = true,
            // 排除的类型是注解类型,排除的注解名称是 Service (也就是排除 @Service 注解标注的类)
            excludeFilters = {
                    @ComponentScan.Filter(type=FilterType.ANNOTATION,classes={Service.class})
            }
        )
    // 配置类
    public class SpringConfiguration {
        @Bean
        public Person person01() {
            return new Person("Bill Gates", 66);
        }
    
        @Bean
        public Person person02() {
            return new Person("Linus Torvalds", 44);
        }
    }

    测试结果:

    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
    springConfiguration
    animal
    userDaoImpl
    person01
    person02

    结果分析:由于我们使用了排除规则,指明了排除 @Service 注解,所以 UserServiceImpl 这个类没有被扫描,也就没有注入到 Spring 容器中

    FilterType.CUSTOM

    枚举值上面的注释可以看出,我们需要实现 TypeFilter 这个接口

    /** Filter candidates using a given custom
     * {@link org.springframework.core.type.filter.TypeFilter} implementation.
     */
    CUSTOM

    自定义一个类 MyCustomTypeFilter 实现 TypeFilter 接口  

    public class MyCustomTypeFilter implements TypeFilter {
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
            // 当前扫描到的注解的元数据
            AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
            // 当前被扫描的类的绝对路径
            Resource resource = metadataReader.getResource();
            // 当前被扫描的类的元数据
            ClassMetadata classMetadata = metadataReader.getClassMetadata();
            // 获取被扫描的类的包类全名
            String className = classMetadata.getClassName();
            // 类名中包含"User"的类
            if(className.contains("User")){
    			// 返回值为 true ,代表的就是要排除
                return true;
            }
            return false;
        }
    }

    配置类

    @Configuration
    // 扫描 com.spring01 包下面的所有注解
    @ComponentScan(value = "com.xiaomaomao",
            // 如果使用的是 excludeFilters, useDefaultFilters 的默认值就是 true,这里可以省略不写
            useDefaultFilters = true,
            // 排除的类型是自定义类型,自定义规则在 MyCustomTypeFilte 类中给出
            excludeFilters = {
                    @ComponentScan.Filter(type=FilterType.CUSTOM,classes={MyCustomTypeFilter.class})
            }
    )
    // 配置类
    public class SpringConfiguration {
        @Bean
        public Person person01() {
            return new Person("Bill Gates", 66);
        }
    
        @Bean
        public Person person02() {
            return new Person("Linus Torvalds", 44);
        }
    }

    测试结果

    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
    springConfiguration
    animal
    person01
    person02
    

    结果分析:类名中包含 "User" 字符串的类都被排除了,最终注入 Spring 容器的类就没有 UserServiceImpl 和 UserDaoImpl

    注意:排除规则只能排除配置类之外的其它类,配置类里面相应的信息是不能被排除的.

    3、includeFilters属性

    Filter[] includeFilters() default {},代表只扫描哪一些类或者是注解(取决于 type 的类型)用法和 excludeFilter 类似,唯一的区别就是,如果你想使用 includeFilter 进行筛选的时候,切记一定要将 useDefaultFilter 这个属性的值设置为 false. 

    4、@ComponentScan 注解是一个可重复注解,我们可以同时定义多个 @Component 注解

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    // 可重复注解
    @Repeatable(ComponentScans.class)
    public @interface ComponentScan {

    例如:

    @Configuration
    @ComponentScans({
            @ComponentScan(value = "com.spring01",
                    useDefaultFilters = false,
                    // 只扫描类名中包含 "Dao"
                    includeFilters = {
                            @ComponentScan.Filter(type=FilterType.CUSTOM,classes={MyCustomTypeFilter.class})
                    }
            ),
            @ComponentScan(value = "com.spring01",
                    useDefaultFilters = false,
                    // 排除 @Service 注解
                    excludeFilters = {
                            @ComponentScan.Filter(type=FilterType.ANNOTATION,classes={Service.class})
                    }
            )
        }
    )
    @ComponentScan(value = "com.spring01",
            // 如果使用的是 excludeFilters, useDefaultFilters的默认值就是 true,这里可以省略不写
            useDefaultFilters = false,
            // 使用自定义的TypeFilter
            includeFilters = {
                    @ComponentScan.Filter(type=FilterType.CUSTOM,classes={MyCustomTypeFilter.class})
            }
        )
    public class SpringConfiguration {
    
        @Bean
        public Person person01() {
            return new Person("Bill Gates", 66);
        }
    
        @Bean
        public Person person02() {
            return new Person("Linus Torvalds", 44);
        }
    }

     

      

  • 相关阅读:
    IIS网站或系统验证码不显示问题——"使用了托管的处理程序,但是未安装或未完整安装 ASP.NET"
    Windows Server 2008 R2 下配置证书服务器和HTTPS方式访问网站
    RESTful API 设计指南
    Js计算当前日,当前周开始结束时间,当前月份,当前年份
    highcharts
    CSS布局 ——从display,position, float属性谈起
    CSS的选择器
    DOC窗口之cd命令(windows)
    Tomcat的启动与关闭以及启动时一闪而过的解决方法
    为什么安装jdk时,会安装两个jre?不用配置jre的环境变量
  • 原文地址:https://www.cnblogs.com/xiaomaomao/p/13532431.html
Copyright © 2020-2023  润新知