【spring 註解】第2篇:@ComponentScan

weixin_33766168發表於2018-08-11

@ComponentScan

用於指定包的掃描路徑。用於代替spring的xml配置檔案中的<context:componet-scan base-package=""/>標籤。

context:componet-scan標籤

context:componet-scan的作用

spring就會去自動掃描base-package對應的路徑或者該路徑的子包下面的帶有@Service,@Component,@Repository,@Controller註解的java檔案。

context:componet-scan屬性

  1. base-package: 指定掃描路徑。
  2. use-default-filters: 是否使用預設的掃描過濾器。
  • use-default-filters=true表示掃描包路徑的@Service,@Component,@Repository,@Controller註解的類;如果你不想全部掃描這些類,可以進行過濾,比如說你不想掃描@Controller註解的類。
<context:componet-scan base-package="com.sff.app" use-default-filters="true">
        <!--不掃描@Controller註解的類-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:componet-scan>
<context:componet-scan base-package="com.sff.app" use-default-filters="false">
        <!--只掃描@Controller註解的類-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:componet-scan>
  • use-default-filters=true表示按照自定義規則掃描包路徑下的類;

@ComponentScan的使用

該註解是使用在我們的配置類上的。

/**
 * 配置類等價於spring的配置檔案
 */
@Configuration
@ComponentScan(value = "com.sff.app",
        includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)},
        useDefaultFilters = false)
public class AppConfig {
    /*給容器中註冊一個bean,型別是方法返回值,id就是方法名稱*/
    @Bean
    public Person person() {
        return new Person("Kate", 12);
    }
}

@ComponentScan的屬性說明

@ComponentScan(value = "com.sff.app",useDefaultFilters = false,
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,
        classes = {Controller.class, Service.class})})

@ComponentScan(value = "com.sff.app",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,
        classes = {Controller.class, Service.class})})
  • useDefaultFilters: 是否使用預設的掃描過濾器,相當於use-default-filters的功能。
  • excludeFilters: 指定掃描時需要按照什麼規則排除不掃描的類。
  • includeFilters: 指定掃描時需要按照什麼規則掃描的類。

我們看下註解原始碼是怎麼定義的?

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    /*定義了包掃描路徑屬性*/
    @AliasFor("basePackages")
    String[] value() default {};
    @AliasFor("value")
    String[] basePackages() default {};
    /*預設使用預設的過濾,全部掃描*/
    boolean useDefaultFilters() default true;
    /*過濾器屬性,過濾器是一個陣列,可以配置多個*/
    ComponentScan.Filter[] includeFilters() default {};
    ComponentScan.Filter[] excludeFilters() default {};
    
    /*過濾器註解*/
    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        /*預設的過濾規則是按照註解來過濾*/
        FilterType type() default FilterType.ANNOTATION;
    }
}
/*Filter中的FilterType支援過濾型別*/
public enum FilterType {
    ANNOTATION, //註解
    ASSIGNABLE_TYPE, //指定型別,比如指定包路徑下的某個具體類
    ASPECTJ,//使用aspectj表示式
    REGEX,//正規表示式
    CUSTOM;//自定義
}

@ComponentScan的自定義掃描規則

  • 實現TypeFilter類
/**
 * 自定義過濾規則
 */
public class CustomFilterType implements TypeFilter {
    /**
     * @param metadataReader        獲取當前正在掃描的類的資訊
     * @param metadataReaderFactory 獲取其他類的資訊
     * @return
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
        /*獲取當前類的註解資訊*/
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        /*獲取當前類的資訊*/
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        /*獲取資原始檔*/
        Resource resource = metadataReader.getResource();

        System.out.println("---------------->" + classMetadata.getClassName());
        /*過濾類全名稱包括HelloController的類*/  
        if (classMetadata.getClassName().contains("HelloController")) {
            return true;
        }
        return false;
    }
}
  • 配置類配置自定義掃描規則
/**
 * 配置類等價於spring的配置檔案
 */
@Configuration
@ComponentScan(value = "com.sff.app",useDefaultFilters = false,
        includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = CustomFilterType.class)})
public class AppConfig {
    /*給容器中註冊一個bean,型別是方法返回值,id就是方法名稱*/
    @Bean
    public Person person() {
        return new Person("Kate", 12);
    }
}
  • 測試類
public class ComponentScanTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        String[] names = ctx.getBeanDefinitionNames();

        for (String name : names) {
            System.out.println(name);
        }
    }
}

結果分析:

//列印出了當前掃描的類的資訊
---------------->com.sff.app.ComponentScanTest
---------------->com.sff.app.ConfigurationTest
---------------->com.sff.app.TestAnno
---------------->com.sff.app.anno.AnnoDemo
---------------->com.sff.app.anno.MyAnnotation
---------------->com.sff.app.anno.Rename
---------------->com.sff.app.bean.Person
---------------->com.sff.app.config.CustomFilterType
---------------->com.sff.app.controller.HelloController
---------------->com.sff.app.service.HelloService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
/*過濾後容器中的類資訊*/
appConfig  //主配置類
helloController 
person //通過@Bean注入的

相關文章