Spring學習----------(1)@ComponentScan註解

1.@ComponentScan 是什麼

主要就是定義掃描的路徑從中找出標識了需要裝配的類自動裝配到spring的bean容器中。註解定義如下

package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    /**
     * 對應的包掃描路徑 可以是單個路徑,也可以是掃描的路徑數組
     * @return
     */
    @AliasFor("basePackages")
    String[] value() default {};
    /**
     * 和value一樣是對應的包掃描路徑 可以是單個路徑,也可以是掃描的路徑數組
     * @return
     */
    @AliasFor("value")
    String[] basePackages() default {};
    /**
     * 指定具體的掃描的類
     * @return
     */
    Class<?>[] basePackageClasses() default {};
    /**
     * 對應的bean名稱的生成器 默認的是BeanNameGenerator
     * @return
     */
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
    /**
     * 處理檢測到的bean的scope範圍
     */
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
    /**
     * 是否爲檢測到的組件生成代理
     * Indicates whether proxies should be generated for detected components, which may be
     * necessary when using scopes in a proxy-style fashion.
     * <p>The default is defer to the default behavior of the component scanner used to
     * execute the actual scan.
     * <p>Note that setting this attribute overrides any value set for {@link #scopeResolver}.
     * @see ClassPathBeanDefinitionScanner#setScopedProxyMode(ScopedProxyMode)
     */
    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
    /**
     * 控制符合組件檢測條件的類文件   默認是包掃描下的  **/*.class
     * @return
     */
    String resourcePattern() default "**/*.class";
    /**
     * 是否對帶有@Component @Repository @Service @Controller註解的類開啓檢測,默認是開啓的
     * @return
     */
    boolean useDefaultFilters() default true;
    /**
     * 指定某些定義Filter滿足條件的組件 FilterType有5種類型如:
     *                                  ANNOTATION, 註解類型 默認
                                        ASSIGNABLE_TYPE,指定固定類
                                        ASPECTJ, ASPECTJ類型
                                        REGEX,正則表達式
                                        CUSTOM,自定義類型
     * @return
     */
    ComponentScan.Filter[] includeFilters() default {};
    /**
     * 排除某些過濾器掃描到的類
     * @return
     */
    ComponentScan.Filter[] excludeFilters() default {};
    /**
     * 掃描到的類是都開啓懶加載 ,默認是不開啓的
     * @return
     */
    boolean lazyInit() default false;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};

        String[] pattern() default {};
    }
}

basePackages與value: 用於指定包的路徑,進行掃描

basePackageClasses: 用於指定某個類的包的路徑進行掃描

nameGenerator: bean的名稱的生成器

useDefaultFilters: 是否開啓對@Component,@Repository,@Service,@Controller的類進行檢測

includeFilters: 包含的過濾條件

        FilterType.ANNOTATION:按照註解過濾

        FilterType.ASSIGNABLE_TYPE:按照給定的類型

        FilterType.ASPECTJ:使用ASPECTJ表達式

        FilterType.REGEX:正則

        FilterType.CUSTOM:自定義規則

excludeFilters: 排除的過濾條件,用法和includeFilters一樣,使用excludeFilters時,useDefaultFilters 要爲true。

2.@ComponentScan註解的詳細使用

做過web開發的同學一定都有用過@Controller,@Service,@Repository註解,查看其源碼你會發現,他們中有一個共同的註解@Component,沒錯@ComponentScan註解默認就會裝配標識了@Controller,@Service,@Repository,@Component註解的類到spring容器中,好下面咱們就先來簡單演示一下這個例子
分別創建帶註解的service,dao,controller類,目錄如下
Controller帶@Controller
Service帶@Service
Dao帶@Repository
在這裏插入圖片描述
再建一個配置類MainConfig

//配置類 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2")
public class MainConfig {

    //給aop容器註冊一個bean,類型爲返回值類型,默認bean id 是方法名,可以自定義  
    @Bean
    public Person person(){
        return new Person("JJJ",12);
    }
}

測試類

測試一:默認攔截規則

@Test
    public void test01(){

        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] names = applicationContext.getBeanDefinitionNames();
        //System.out.println(names);
        for (String name : names) {
            System.out.println(name);
        }
    }`

測試結果:
在這裏插入圖片描述
把所有帶註解的bean都註冊進去了

測試二:includeFilters 修改Mainconfig如下,使用註解攔截器。過濾類型是ANNOTATION(註解),只過濾controller,關閉默認的過濾器

//配置類 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
},useDefaultFilters = false)
public class MainConfig {

    //給aop容器註冊一個bean,類型爲返回值類型,默認bean id 是方法名,可以自定義  
    @Bean
    public Person person(){
        return new Person("JJJ",12);
    }
}

運行測試類,測試結果:
在這裏插入圖片描述
除了自己本身和自定義的bean之外,系統只注入了controller

測試三:excludeFilters 修改Mainconfig如下,使用註解攔截器。過濾類型是ANNOTATION(註解),排除controller,開啓默認的過濾器

//配置類 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
},useDefaultFilters = true)
public class MainConfig {

    //給aop容器註冊一個bean,類型爲返回值類型,默認bean id 是方法名,可以自定義  
    @Bean
    public Person person(){
        return new Person("JJJ",12);
    }
}

測試結果:沒有註冊controller類
在這裏插入圖片描述
測試四:過濾方式爲 ASSIGNABLE_TYPE,指定過濾類型,配置類如下

//配置類 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {OrderController.class})
},useDefaultFilters = false)
public class MainConfig {

    //給aop容器註冊一個bean,類型爲返回值類型,默認bean id 是方法名,可以自定義  
    @Bean
    public Person person(){
        return new Person("JJJ",12);
    }
}

測試結果:只有指定的orderController類被註冊進容器
在這裏插入圖片描述
測試五:自定義過濾方式
1.新建一個CustomTypeFilter類實現TypeFilter接口,並實現其 match 方法。

public class CustomTypeFilter implements TypeFilter {
    /**
     *
     * @param metadataReader:讀取到當前正在掃描類的信息
     * @param metadataReaderFactory:可以獲取到其任何類信息
     * @return
     * @throws IOException
     */
    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("con")){ //當類包含con字符串,匹配成功,返回true
            return true;
        }

        return false;
    }

這裏簡單對掃描到的類名進行判斷,如果類名包含”con“的就符合條件,也就會注入到容器中。
2.修改配置類:type = FilterType.CUSTOM, classes = {CustomTypeFilter.class}

//配置類 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {CustomTypeFilter.class})
},useDefaultFilters = false)
public class MainConfig {

    //給aop容器註冊一個bean,類型爲返回值類型,默認bean id 是方法名,可以自定義  
    @Bean
    public Person person(){
        return new Person("JJJ",12);
    }
}

測試結果:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章