1

@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注入的

一只小小鸟
144 声望25 粉丝

如何做一个深层次的思考者,从简单开始、从记录开始。