spring 注解学习 二 ComponentScan注解的使用

@ComponentScan 的作用就是根据定义的扫描路径,把符合扫描规则的类装配到spring容器中,注解定义如下。

 

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.TYPE})

@Documented

@Repeatable(ComponentScans.class)

public @interface ComponentScan {

    @AliasFor("basePackages")

    String[] value() default {};

 

    @AliasFor("value")

    String[] basePackages() default {};

 

    Class<?>[] basePackageClasses() default {};

 

    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

 

    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

 

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

 

    String resourcePattern() default "**/*.class";



    boolean useDefaultFilters() default true;



    ComponentScan.Filter[] includeFilters() default {};



    ComponentScan.Filter[] excludeFilters() default {};



    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的类进行检测
(1)默认情况下是true。在basePackages指定的路径以及子路径下所有被@Component ,@Repository,@Service,@Controller注解标记的类都会被扫描,并注入到Spring 容器。
(2)如果useDefaultFilters的是false话,不扫描 在basePackages指定的路径以及子路径下所有被@Component ,@Repository,@Service,@Controller注解标记的类,这些类即使被上面四个注解标记,也不会注入到Spring容器中。
 
 

includeFilters:

包含的过滤条件,一般当useDefaultFilters的值为false时使用,当useDefaultFilters为false时,includeFilters指定的就是需要进行扫描并注入的条件
            FilterType.ANNOTATION:按照注解过滤
            FilterType.ASSIGNABLE_TYPE:按照给定的类型
            FilterType.ASPECTJ:使用ASPECTJ表达式
            FilterType.REGEX:正则
            FilterType.CUSTOM:自定义规则
 
 

excludeFilters:

排除的过滤条件,一般useDefaultFilters为true时使用,excludeFilters的指就是basePackages指定的路径以及子路径下排除的条件。
 

案例1

 
 
@Configuration
@ComponentScan(basePackages = {"com.zhang"},
useDefaultFilters=true,
excludeFilters ={@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
        @Filter(type=FilterType.ANNOTATION,classes={Service.class})})

 

(1)basePaceages指定了 com.zhang这个包,useDefaultFilters的值为true。如果不考虑excludeFilters ,这个两个属性组合的起来就是在 com.zhang及其子包下所有被@Component ,@Repository,@Service,@Controller这四个注解标注的类,都会被扫描并注入到Spring容器中。

(2)excludeFilters 属性指定了要排除掉被@Controller与@Service两个注解。在basePaceages与useDefaultFilters两个属性的基础上进行排除,那么最后扫描的就是 com.zhang包及其子包下的被@Component ,@Repository标记的类。

 

案例2

@ComponentScan(basePackages = {"com.zhang"},
useDefaultFilters=false,
includeFilters ={@Filter(type=FilterType.ANNOTATION,classes={Controller.class})})

includeFilters 也是在basePackages与useDefaultFilters组合后的基础上添加一些特定的类。本例中的意思是只扫描com.zhang及其子包下被@Controller注解标记的类

  

案例3 自定义规则   FilterType.CUSTOM

@Configuration
@ComponentScan(value = "com.personal.spring.bean",useDefaultFilters = true,
        excludeFilters ={@ComponentScan.Filter(type= FilterType.CUSTOM,classes= MyTypeFilter.class)}
)
public class SpringConfig {
}

 

在com.personal.spring.bean包下有bean

package com.personal.spring.bean;

import lombok.Data;
import org.springframework.stereotype.Component;

@Data
@Component
public class User {
    private String userName;
    private String userCode;
}
MyTypeFilter过滤器
package com.personal.spring.filter;

import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;

public class MyTypeFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        System.out.println(annotationMetadata.getAnnotationTypes());
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        System.out.println(classMetadata.getClassName());
        Resource resource = metadataReader.getResource();
        System.out.println(resource.getFilename());

        System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++");
        return true;
    }
}

 

 测试代码:
package com.personal.spring.main;

import com.personal.spring.config.SpringConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Arrays;

public class Main {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
        String[] beanDefinitionNames = context.getBeanDefinitionNames();

        Arrays.stream(beanDefinitionNames).forEach(x-> System.out.println(x));
    }
}

 

运行结果:

[org.springframework.stereotype.Component]
com.personal.spring.bean.User
User.class
++++++++++++++++++++++++++++++++++++++++++++++++++
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
springConfig

 

案例三中,我们发现useDefaultFilters等于true的情况下,User类也被@Componet注解标注的情况下,还是没有注入到容器。原因就是在

excludeFilters中使用自定义规则,如果返回true 是排除当前的类,如果返回false,是把当前类加入到容器、
includeFilters中使用自定义规则,如果返回true,是把当前类加入到容器,如果返回false则是把当前类排除
 
posted @ 2020-03-10 16:37  阿瞒123  阅读(323)  评论(0编辑  收藏  举报