溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

spring中@ComponentScan注解的使用介紹

發(fā)布時間:2021-08-16 15:02:18 來源:億速云 閱讀:220 作者:chen 欄目:開發(fā)技術(shù)

這篇文章主要介紹“spring中@ComponentScan注解的使用介紹”,在日常操作中,相信很多人在spring中@ComponentScan注解的使用介紹問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”spring中@ComponentScan注解的使用介紹”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

目錄
  • @ComponentScan注解的使用

    • 一、注解定義

    • 二、使用

      • 1.環(huán)境準(zhǔn)備

      • 2.excludeFilters的使用

      • 3.includeFilters的使用

      • 4.自定義過濾規(guī)則

  • 關(guān)于@ComponentScan注解的一些細(xì)節(jié)

    @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,可以自定義實(shí)現(xiàn)命名Bean,
        * 1、@ComponentScan(value = "spring.annotation.componentscan",nameGenerator = MyBeanNameGenerator.class)
        * MyBeanNameGenerator.class 需要實(shí)現(xiàn) BeanNameGenerator 接口,所有實(shí)現(xiàn)BeanNameGenerator 接口的實(shí)現(xiàn)類都會被調(diào)用
        * 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 方法重新設(shè)定處理類
        * ScopeMetadataResolver scopeMetadataResolver = definition -> new ScopeMetadata();  這里只是new了一個對象作為演示,沒有做實(shí)際的邏輯操作
        * AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        * annotationConfigApplicationContext.setScopeMetadataResolver(scopeMetadataResolver);
        * annotationConfigApplicationContext.register(MainConfig2.class);
        * annotationConfigApplicationContext.refresh();
        * 也可以通過@ComponentScan 的 scopeResolver 屬性設(shè)置
        *@ComponentScan(value = "spring.annotation.componentscan",scopeResolver = MyAnnotationScopeMetadataResolver.class)
        */
       Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
       /**
        * 用來設(shè)置類的代理模式
        */
       ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
       /**
        * 掃描路徑 如 resourcePattern = "**/*.class"
        * 使用  includeFilters 和 excludeFilters 會更靈活
        */
       String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
       /**
        * 指示是否應(yīng)啟用對帶有{@code @Component},{@ code @Repository},
        * {@ code @Service}或{@code @Controller}注釋的類的自動檢測。
        */
       boolean useDefaultFilters() default true;
       /**
        * 對被掃描的包或類進(jìn)行過濾,若符合條件,不論組件上是否有注解,Bean對象都將被創(chuàng)建
        * @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 必須設(shè)為 false
        */
       Filter[] includeFilters() default {};
       /**
        * 指定哪些類型不適合進(jìn)行組件掃描。
        * 用法同 includeFilters 一樣
        */
       Filter[] excludeFilters() default {};
       /**
        * 指定是否應(yīng)注冊掃描的Bean以進(jìn)行延遲初始化。
        * @ComponentScan(value = "spring.annotation.componentscan",lazyInit = true)
        */
       boolean lazyInit() default false;
       /**
        * 用于 includeFilters 或 excludeFilters 的類型篩選器
        */
       @Retention(RetentionPolicy.RUNTIME)
       @Target({})
       @interface Filter {
          /**
           * 要使用的過濾器類型,默認(rèn)為 ANNOTATION 注解類型
           * @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
           */
          FilterType type() default FilterType.ANNOTATION;
          /**
           * 過濾器的參數(shù),參數(shù)必須為class數(shù)組,單個參數(shù)可以不加大括號
           * 只能用于 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 參數(shù)為注解類,如  Controller.class, Service.class, Repository.class
           * ASSIGNABLE_TYPE 參數(shù)為類,如 SchoolDao.class
           * CUSTOM  參數(shù)為實(shí)現(xiàn) TypeFilter 接口的類 ,如 MyTypeFilter.class
           * MyTypeFilter 同時還能實(shí)現(xiàn) EnvironmentAware,BeanFactoryAware,BeanClassLoaderAware,ResourceLoaderAware 
           * 這四個接口
           * EnvironmentAware
           * 此方法用來接收 Environment 數(shù)據(jù) ,主要為程序的運(yùn)行環(huán)境,Environment 接口繼承自 PropertyResolver 接口,
           * 詳細(xì)內(nèi)容在下方
           * @Override
           * public void setEnvironment(Environment environment) {
           *    String property = environment.getProperty("os.name");
           * }
           * 
           * BeanFactoryAware
           * BeanFactory Bean容器的根接口,用于操作容器,如獲取bean的別名、類型、實(shí)例、是否單例的數(shù)據(jù)
           * @Override
           * public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
           *     Object bean = beanFactory.getBean("BeanName")
           * }
           * 
           * BeanClassLoaderAware
           * ClassLoader 是類加載器,在此方法里只能獲取資源和設(shè)置加載器狀態(tài)
           * @Override
           * public void setBeanClassLoader(ClassLoader classLoader) {
           *     ClassLoader parent = classLoader.getParent();
           * }
           * 
           * ResourceLoaderAware
           * ResourceLoader 用于獲取類加載器和根據(jù)路徑獲取資源
           * public void setResourceLoader(ResourceLoader resourceLoader) {
           *     ClassLoader classLoader = resourceLoader.getClassLoader();
           * }
           */
          @AliasFor("value")
          Class<?>[] classes() default {};
          /**
           * 這個參數(shù)是 classes 或 value 的替代參數(shù),主要用于 ASPECTJ 類型和  REGEX 類型
           * ASPECTJ  為 ASPECTJ 表達(dá)式
           * @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = "spring.annotation..*")
           * REGEX  參數(shù)為 正則表達(dá)式
           * @ComponentScan.Filter(type = FilterType.REGEX, pattern = "^[A-Za-z.]+Dao$")
           */
          String[] pattern() default {};
       }
    }

    二、使用

    1.環(huán)境準(zhǔn)備

    創(chuàng)建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>

    創(chuàng)建bean,controller,dao,service層,并在類上加上對應(yīng)的注解,項目結(jié)構(gòu)如下:

    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用于設(shè)置排除的過濾條件,實(shí)現(xiàn)Filter接口的type屬性用于設(shè)置過濾類型,默認(rèn)值為FilterType.ANNOTATION,提供了這幾個過濾類型:

    • FilterType.ANNOTATION:按照注解過濾

    • FilterType.ASSIGNABLE_TYPE:按照給定的類型過濾

    • FilterType.ASPECTJ:按照ASPECTJ表達(dá)式過濾

    • FilterType.REGEX:按照正則表達(dá)式過濾

    • FilterType.CUSTOM:按照自定義規(guī)則過濾

    classes和value屬性為過濾器的參數(shù),必須為class數(shù)組,類只能為以下三種類型:

    • ANNOTATION 參數(shù)為注解類,如 Controller.class, Service.class,Repository.class

    • ASSIGNABLE_TYPE 參數(shù)為類,如 SchoolDao.class

    • CUSTOM 參數(shù)為實(shí)現(xiàn) TypeFilter 接口的類 ,如 MyTypeFilter.class

    3.includeFilters的使用

    includeFilters屬性用于定義掃描過濾條件,滿足該條件才進(jìn)行掃描。用法與excludeFilters一樣。

    但是因?yàn)閡seDefaultFilters屬性默認(rèn)為true,即使用默認(rèn)的過濾器,啟用對帶有@Component,@Repository,@Service,@Controller注釋的類的自動檢測。會將帶有這些注解的類注冊為bean裝配到IoC容器中。所以使用includeFilters時,需要把useDefaultFilters設(shè)置為false,如下:

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

    結(jié)果如下,只掃描了帶有Controller,Service注解的自定義的類:

    spring中@ComponentScan注解的使用介紹

    4.自定義過濾規(guī)則

    @ComponentScan注解掃描或解析的bean只能是Spring內(nèi)部所定義的,比如@Component、@Service、@Controller或@Repository。如果要掃描一些自定義的注解,就可以自定義過濾規(guī)則來完成這個操作。

    自定義一個類MyTypeFilter實(shí)現(xiàn)TypeFilter接口,這樣這個TypeFilter就掃描所有類并只通過類名包含了controller的類,如下:

    public class MyTypeFilter implements TypeFilter {
        /**
         * 兩個參數(shù)的含義:
         * metadataReader:包含讀取到的當(dāng)前正在掃描的類的信息
         * metadataReaderFactory:可以獲取到當(dāng)前正在掃描的類的其他類信息(如父類和接口)
         * match方法返回false即不通過過濾規(guī)則,true通過過濾規(guī)則
         */
    	@Override
    	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
    			throws IOException {
    		// TODO Auto-generated method stub
    	     //獲取當(dāng)前類注解的信息
            AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
            //獲取當(dāng)前正在掃描的類的類信息
            ClassMetadata classMetadata = metadataReader.getClassMetadata();
            //獲取當(dāng)前類資源(類的路徑)
            Resource resource = metadataReader.getResource();
            String className = classMetadata.getClassName();
            if(className.contains("controller")){
                return true;
            }
            return false;
    	}
    }

    在@ComponentScan注解中進(jìn)行配置,如下:

    @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 {
    }

    經(jīng)過上面的配置,第一個@Filter通過FilterType.ASSIGNABLE_TYPE規(guī)定了只掃描Person類型的類,第二個@Filter通過FilterType.CUSTOM自定義過濾規(guī)則規(guī)定了只掃描類名包含controller的類。結(jié)果:

    spring中@ComponentScan注解的使用介紹

    關(guān)于@ComponentScan注解的一些細(xì)節(jié)

    @ComponentScan注解可以掃描 任意 類 或者 注解 中內(nèi)部類bean;

    要想被掃描的前提是內(nèi)部類標(biāo)注了@Component及其相關(guān)衍生注解、內(nèi)部類必須是static修飾,否則掃描不到;如果是注解的內(nèi)部類則只能是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"; //屬性可以
        //內(nèi)部類可以
        @Component
        @DependsOn("myBean.EventZ") //依賴事件bean的創(chuàng)建,保證該bean在事件bean之后創(chuàng)建
            //細(xì)節(jié):因?yàn)槭莾?nèi)部類,所以默認(rèn)bean的id是類名首字母小寫,不是eventZ而是myBean.EventZ
        class EventSource {
            public EventSource(){
                System.out.println("事件源創(chuàng)建了...");
            }
        }
        @Component//("eventZ")
        public static class EventZ {
            public EventZ(){
                System.out.println("事件創(chuàng)建了...");
            }
        }
    }

    到此,關(guān)于“spring中@ComponentScan注解的使用介紹”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI