温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

spring中@ComponentScan注解的使用介绍

发布时间:2021-08-16 15:02:18 来源:亿速云 阅读:208 作者:chen 栏目:开发技术

这篇文章主要介绍“spring中@ComponentScan注解的使用介绍”,在日常操作中,相信很多人在spring中@ComponentScan注解的使用介绍问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”spring中@ComponentScan注解的使用介绍”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

目录
  • @ComponentScan注解的使用

    • 一、注解定义

    • 二、使用

      • 1.环境准备

      • 2.excludeFilters的使用

      • 3.includeFilters的使用

      • 4.自定义过滤规则

  • 关于@ComponentScan注解的一些细节

    @ComponentScan注解的使用

    一、注解定义

    @ComponentScan注解的定义如下:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    @Documented
    @Repeatable(ComponentScans.class)
    public @interface ComponentScan {
       /**
        * 扫描路径
        * @ComponentScan(value = "spring.annotation.componentscan")
        */
       @AliasFor("basePackages")
       String[] value() default {};
       /**
        * 扫描路径
        */
       @AliasFor("value")
       String[] basePackages() default {};
       /**
        * 指定扫描类
        * @ComponentScan(basePackageClasses = {BookDao.class, BookService.class})
        */
       Class<?>[] basePackageClasses() default {};
       /**
        * 命名注册的Bean,可以自定义实现命名Bean,
        * 1、@ComponentScan(value = "spring.annotation.componentscan",nameGenerator = MyBeanNameGenerator.class)
        * MyBeanNameGenerator.class 需要实现 BeanNameGenerator 接口,所有实现BeanNameGenerator 接口的实现类都会被调用
        * 2、使用 AnnotationConfigApplicationContext 的 setBeanNameGenerator方法注入一个BeanNameGenerator
        * BeanNameGenerator beanNameGenerator = (definition,registry)-> String.valueOf(new Random().nextInt(1000));
        * AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        * annotationConfigApplicationContext.setBeanNameGenerator(beanNameGenerator);
        * annotationConfigApplicationContext.register(MainConfig2.class);
        * annotationConfigApplicationContext.refresh();
        * 第一种方式只会重命名@ComponentScan扫描到的注解类
        * 第二种只有是初始化的注解类就会被重命名
        * 列如第一种方式不会重命名 @Configuration 注解的bean名称,而第二种就会重命名 @Configuration 注解的Bean名称
        */
       Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
       /**
        * 用于解析@Scope注解,可通过 AnnotationConfigApplicationContext 的 setScopeMetadataResolver 方法重新设定处理类
        * ScopeMetadataResolver scopeMetadataResolver = definition -> new ScopeMetadata();  这里只是new了一个对象作为演示,没有做实际的逻辑操作
        * AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        * annotationConfigApplicationContext.setScopeMetadataResolver(scopeMetadataResolver);
        * annotationConfigApplicationContext.register(MainConfig2.class);
        * annotationConfigApplicationContext.refresh();
        * 也可以通过@ComponentScan 的 scopeResolver 属性设置
        *@ComponentScan(value = "spring.annotation.componentscan",scopeResolver = MyAnnotationScopeMetadataResolver.class)
        */
       Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
       /**
        * 用来设置类的代理模式
        */
       ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
       /**
        * 扫描路径 如 resourcePattern = "**/*.class"
        * 使用  includeFilters 和 excludeFilters 会更灵活
        */
       String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
       /**
        * 指示是否应启用对带有{@code @Component},{@ code @Repository},
        * {@ code @Service}或{@code @Controller}注释的类的自动检测。
        */
       boolean useDefaultFilters() default true;
       /**
        * 对被扫描的包或类进行过滤,若符合条件,不论组件上是否有注解,Bean对象都将被创建
        * @ComponentScan(value = "spring.annotation.componentscan",includeFilters = {
        *     @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}),
        *     @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {SchoolDao.class}),
        *     @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}),
        *     @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "spring.annotation..*"),
        *     @ComponentScan.Filter(type = FilterType.REGEX, pattern = "^[A-Za-z.]+Dao$")
        * },useDefaultFilters = false)
        * useDefaultFilters 必须设为 false
        */
       Filter[] includeFilters() default {};
       /**
        * 指定哪些类型不适合进行组件扫描。
        * 用法同 includeFilters 一样
        */
       Filter[] excludeFilters() default {};
       /**
        * 指定是否应注册扫描的Bean以进行延迟初始化。
        * @ComponentScan(value = "spring.annotation.componentscan",lazyInit = true)
        */
       boolean lazyInit() default false;
       /**
        * 用于 includeFilters 或 excludeFilters 的类型筛选器
        */
       @Retention(RetentionPolicy.RUNTIME)
       @Target({})
       @interface Filter {
          /**
           * 要使用的过滤器类型,默认为 ANNOTATION 注解类型
           * @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
           */
          FilterType type() default FilterType.ANNOTATION;
          /**
           * 过滤器的参数,参数必须为class数组,单个参数可以不加大括号
           * 只能用于 ANNOTATION 、ASSIGNABLE_TYPE 、CUSTOM 这三个类型
           * @ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class, Service.class})
           * @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {SchoolDao.class})
           * @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
           */
          @AliasFor("classes")
          Class<?>[] value() default {};
          /**
           * 作用同上面的 value 相同
           * ANNOTATION 参数为注解类,如  Controller.class, Service.class, Repository.class
           * ASSIGNABLE_TYPE 参数为类,如 SchoolDao.class
           * CUSTOM  参数为实现 TypeFilter 接口的类 ,如 MyTypeFilter.class
           * MyTypeFilter 同时还能实现 EnvironmentAware,BeanFactoryAware,BeanClassLoaderAware,ResourceLoaderAware 
           * 这四个接口
           * EnvironmentAware
           * 此方法用来接收 Environment 数据 ,主要为程序的运行环境,Environment 接口继承自 PropertyResolver 接口,
           * 详细内容在下方
           * @Override
           * public void setEnvironment(Environment environment) {
           *    String property = environment.getProperty("os.name");
           * }
           * 
           * BeanFactoryAware
           * BeanFactory Bean容器的根接口,用于操作容器,如获取bean的别名、类型、实例、是否单例的数据
           * @Override
           * public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
           *     Object bean = beanFactory.getBean("BeanName")
           * }
           * 
           * BeanClassLoaderAware
           * ClassLoader 是类加载器,在此方法里只能获取资源和设置加载器状态
           * @Override
           * public void setBeanClassLoader(ClassLoader classLoader) {
           *     ClassLoader parent = classLoader.getParent();
           * }
           * 
           * ResourceLoaderAware
           * ResourceLoader 用于获取类加载器和根据路径获取资源
           * public void setResourceLoader(ResourceLoader resourceLoader) {
           *     ClassLoader classLoader = resourceLoader.getClassLoader();
           * }
           */
          @AliasFor("value")
          Class<?>[] classes() default {};
          /**
           * 这个参数是 classes 或 value 的替代参数,主要用于 ASPECTJ 类型和  REGEX 类型
           * ASPECTJ  为 ASPECTJ 表达式
           * @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "spring.annotation..*")
           * REGEX  参数为 正则表达式
           * @ComponentScan.Filter(type = FilterType.REGEX, pattern = "^[A-Za-z.]+Dao$")
           */
          String[] pattern() default {};
       }
    }

    二、使用

    1.环境准备

    创建Maven项目,添加依赖:

      <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    		<dependency>
    		    <groupId>org.springframework</groupId>
    		    <artifactId>spring-context</artifactId>
    		    <version>4.3.26.RELEASE</version>
    		</dependency>
    		<!-- https://mvnrepository.com/artifact/junit/junit -->
    		<dependency>
    		  <groupId>junit</groupId>
    			<artifactId>junit</artifactId>
    			<version>4.12</version>
    			<scope>test</scope>
    		</dependency>	
      </dependencies>

    创建bean,controller,dao,service层,并在类上加上对应的注解,项目结构如下:

    spring中@ComponentScan注解的使用介绍

    编写测试类,如下:

    public class IoCTest {
    	@Test
    	public void test01() {
    		//获取Spring的IOC容器
    		ApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);
    		//从容器中获取bean
    	    String[] names= applicationContext.getBeanDefinitionNames();	
    	       for(String i:names) {
    	    	   System.out.println(i);
    	       }
    	}
    }
    2.excludeFilters的使用

    使用excludeFilters不扫描com.learn包中的Controller、Service注解,如下:

    @Configuration
    @ComponentScan(basePackages = "com.learn",excludeFilters = {
      @Filter(type = FilterType.ANNOTATION,classes = {Controller.class,Service.class})
    })
    public class SpringConfig {
    }

    上面使用的excludeFilters用于设置排除的过滤条件,实现Filter接口的type属性用于设置过滤类型,默认值为FilterType.ANNOTATION,提供了这几个过滤类型:

    • FilterType.ANNOTATION:按照注解过滤

    • FilterType.ASSIGNABLE_TYPE:按照给定的类型过滤

    • FilterType.ASPECTJ:按照ASPECTJ表达式过滤

    • FilterType.REGEX:按照正则表达式过滤

    • FilterType.CUSTOM:按照自定义规则过滤

    classes和value属性为过滤器的参数,必须为class数组,类只能为以下三种类型:

    • ANNOTATION 参数为注解类,如 Controller.class, Service.class,Repository.class

    • ASSIGNABLE_TYPE 参数为类,如 SchoolDao.class

    • CUSTOM 参数为实现 TypeFilter 接口的类 ,如 MyTypeFilter.class

    3.includeFilters的使用

    includeFilters属性用于定义扫描过滤条件,满足该条件才进行扫描。用法与excludeFilters一样。

    但是因为useDefaultFilters属性默认为true,即使用默认的过滤器,启用对带有@Component,@Repository,@Service,@Controller注释的类的自动检测。会将带有这些注解的类注册为bean装配到IoC容器中。所以使用includeFilters时,需要把useDefaultFilters设置为false,如下:

    @Configuration
    @ComponentScan(basePackages = "com.learn",includeFilters = {
      @Filter(type = FilterType.ANNOTATION,classes = {Controller.class,Service.class})
    },useDefaultFilters = false)
    public class SpringConfig {
    }

    结果如下,只扫描了带有Controller,Service注解的自定义的类:

    spring中@ComponentScan注解的使用介绍

    4.自定义过滤规则

    @ComponentScan注解扫描或解析的bean只能是Spring内部所定义的,比如@Component、@Service、@Controller或@Repository。如果要扫描一些自定义的注解,就可以自定义过滤规则来完成这个操作。

    自定义一个类MyTypeFilter实现TypeFilter接口,这样这个TypeFilter就扫描所有类并只通过类名包含了controller的类,如下:

    public class MyTypeFilter implements TypeFilter {
        /**
         * 两个参数的含义:
         * metadataReader:包含读取到的当前正在扫描的类的信息
         * metadataReaderFactory:可以获取到当前正在扫描的类的其他类信息(如父类和接口)
         * match方法返回false即不通过过滤规则,true通过过滤规则
         */
    	@Override
    	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
    			throws IOException {
    		// TODO Auto-generated method stub
    	     //获取当前类注解的信息
            AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
            //获取当前正在扫描的类的类信息
            ClassMetadata classMetadata = metadataReader.getClassMetadata();
            //获取当前类资源(类的路径)
            Resource resource = metadataReader.getResource();
            String className = classMetadata.getClassName();
            if(className.contains("controller")){
                return true;
            }
            return false;
    	}
    }

    在@ComponentScan注解中进行配置,如下:

    @Configuration
    @ComponentScan(basePackages = "com.learn",includeFilters = {
    		@Filter(type = FilterType.ASSIGNABLE_TYPE,classes = {Person.class}),
    		@Filter(type = FilterType.CUSTOM,classes = {MyTypeFilter.class}),
    },useDefaultFilters = false)
    public class SpringConfig {
    }

    经过上面的配置,第一个@Filter通过FilterType.ASSIGNABLE_TYPE规定了只扫描Person类型的类,第二个@Filter通过FilterType.CUSTOM自定义过滤规则规定了只扫描类名包含controller的类。结果:

    spring中@ComponentScan注解的使用介绍

    关于@ComponentScan注解的一些细节

    @ComponentScan注解可以扫描 任意 类 或者 注解 中内部类bean;

    要想被扫描的前提是内部类标注了@Component及其相关衍生注解、内部类必须是static修饰,否则扫描不到;如果是注解的内部类则只能是public static修饰

    //@Configuration
    public class ProfileConfig {
        @Component("class1")
        private static class Class1 {
            @Bean
            public Class3 class3() {
                return new Class3();
            }
        }
        @Component("class2")
        static class Class2 {
        }
        //@Component("class3")
        protected static class Class3 {
        }
    //    @Component("class4") //出错
    //    protected class Class4 {
    //
    //    }
    }
    --------------------------------------------------------
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    //@Bean
    public @interface MyBean {
        public static final int age1=3; //常量可以
        int age=2;
        public abstract String value() default "qwer"; //属性可以
        //内部类可以
        @Component
        @DependsOn("myBean.EventZ") //依赖事件bean的创建,保证该bean在事件bean之后创建
            //细节:因为是内部类,所以默认bean的id是类名首字母小写,不是eventZ而是myBean.EventZ
        class EventSource {
            public EventSource(){
                System.out.println("事件源创建了...");
            }
        }
        @Component//("eventZ")
        public static class EventZ {
            public EventZ(){
                System.out.println("事件创建了...");
            }
        }
    }

    到此,关于“spring中@ComponentScan注解的使用介绍”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI