【Spring注解】2.@ComponentScan注解

微信公众号:程序yuan
关注可了解更多的资源。问题或建议,请公众号留言;

2.@ComponentScan

1.使用xml配置包扫描的方式

<!--包扫描,只要标注了@Controller/@Service/@Repository/@Component就可以被扫描到-->
<context:component-scan base-package="com.ooyhao"></context:component-scan>

 

定义相应的Controller,service,dao层,并用相应的注解进行标注。

2.使用注解方式进行包扫描

//配置类==配置文件
@ComponentScan(value = {"com.ooyhao"})//可以定义多个。
@Configuration //告诉Spring这是一个配置类
public class MainConfig {

    // 给容器中注册一个Bean,类型就是返回值的类型,id默认是用方法名作为id、
    @Bean("person")
    public Person person01(){
        return new Person("李四",20);
    }
}

注意:

    xml方式,<context:component-scan></context:component-scan>是配置在beans.xml文件中的,所以只需要在MainConfig类上用@ComponentScan(value/basePackages="")来进行扫描。(value与basePackages作用一致)。

可以定义多个:(部分源码)

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {

    /**
     * Alias for {@link #basePackages}.
     * <p>Allows for more concise annotation declarations if no other attributes
     * are needed &mdash; for example, {@code @ComponentScan("org.my.pkg")}
     * instead of {@code @ComponentScan(basePackages = "org.my.pkg")}.
     */
    @AliasFor("basePackages")
    String[] value() default {};

    /**
     * Base packages to scan for annotated components.
     * <p>{@link #value} is an alias for (and mutually exclusive with) this
     * attribute.
     * <p>Use {@link #basePackageClasses} for a type-safe alternative to
     * String-based package names.
     */
    @AliasFor("value")
    String[] basePackages() default {};

    /**
     * Type-safe alternative to {@link #basePackages} for specifying the packages
     * to scan for annotated components. The package of each class specified will be scanned.
     * <p>Consider creating a special no-op marker class or interface in each package
     * that serves no purpose other than being referenced by this attribute.
     */
    Class<?>[] basePackageClasses() default {};

测试代码:

@Test
public void testComponent(){
    AnnotationConfigApplicationContext context = new 
        AnnotationConfigApplicationContext(MainConfig.class);
    String[] names = context.getBeanDefinitionNames();
    for(String name:names){
        System.out.println(name);
    }
}

结果:

 

 

3.@Component的扫描规则

1.FilterType的源码(取值):

public enum FilterType {
    ANNOTATION,         //按照注解的方式
    ASSIGNABLE_TYPE,    //按照给定的类型
    ASPECTJ,            //按照ASPECTJ表达式
    REGEX,              //按照正则表达式
    CUSTOM              //自定义
}

2.@Componenet的源码

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)  //可以重复,说明可以写多个ComponentScan
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 ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;

    boolean useDefaultFilters() default true;

    Filter[] includeFilters() default {};

    Filter[] excludeFilters() default {};

    boolean lazyInit() default false;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    @interface Filter {

        FilterType type() default FilterType.ANNOTATION;

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

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

        String[] pattern() default {};

    }

}

3.MainConfig.java(排除)

//配置类==配置文件
@ComponentScan(value = {"com.ooyhao"},excludeFilters = {
        @Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
        @Filter(type = FilterType.ASSIGNABLE_TYPE,value = {BookService.class})
})
@Configuration //告诉Spring这是一个配置类
public class MainConfig {

    // 给容器中注册一个Bean,类型就是返回值的类型,id默认是用方法名作为id、
    @Bean("person")
    public Person person01(){
        return new Person("李四",20);
    }

}

(排除了@Controller标注的,以及BookService类型的)

 

4.MainConfig.java(包含)

xml方式:

<!--包扫描,只要标注了@Controller/@Service/@Repository/@Component就可以被扫描到-->
<context:component-scan base-package="com.ooyhao" use-default-filters="false"></context:component-scan>
<!--需要使用use-default-filters来禁用默认的扫描规则-->

注解方式:

//配置类==配置文件
/*@ComponentScan(value = {"com.ooyhao"},excludeFilters = {
        @Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
        @Filter(type = FilterType.ASSIGNABLE_TYPE,value = {BookService.class})
})*/
@ComponentScan(basePackages = "com.ooyhao",includeFilters = {
        @Filter(type = FilterType.ANNOTATION,value = {Controller.class})
},useDefaultFilters = false)
@Configuration //告诉Spring这是一个配置类
public class MainConfig {

(只包含@Controller标注的)

 

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)  //可以重复,说明可以写多个ComponentScan
public @interface ComponentScan {

可同时写多个@ComponentScan(JDK1.8)。也可以使用@ComponentScans();

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
    ComponentScan[] value();
}

(配置多个@ComponentScan)

@ComponentScan(basePackages = "com.ooyhao",includeFilters = {
        @Filter(type = FilterType.ANNOTATION,value = {Controller.class})//(按照注解)
},useDefaultFilters = false)
@ComponentScan(basePackages = "com.ooyhao",includeFilters = {
        @Filter(type = FilterType.ANNOTATION,value = {Service.class})//包括子类(按照指定类型)
},useDefaultFilters = false)
@Configuration //告诉Spring这是一个配置类
public class MainConfig {

 

5.自定义扫描规则

通过实现TypeFilter接口来自定义扫描规则的Filter

public interface TypeFilter {

    /**
     * @param metadataReader :当前正在扫描的类的信息
     * @param metadataReaderFactory :可以获取到其他类的信息
     */
    boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException;
}

自定义扫描过滤器

public class MyTypeFilter implements TypeFilter{

    /**
     * @param metadataReader :当前正在扫描的类的信息
     * @param metadataReaderFactory :可以获取到其他类的信息
     */
    @Override
    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(annotationMetadata.getAnnotationTypes());//获得注解类型
        System.out.println(resource.getURL());//获得资源路径
        System.out.println(classMetadata.getClassName());//获得类名

        if(classMetadata.getClassName().contains("er")) {
            return true;
        }
        return false;
    }
}

在Config.java上配置

@ComponentScan(basePackages = "com.ooyhao",includeFilters = {
        /*@Filter(type = FilterType.ANNOTATION,value = {Controller.class}),*/
        @Filter(type = FilterType.CUSTOM,value = {MyTypeFilter.class})
},useDefaultFilters = false)
@Configuration //告诉Spring这是一个配置类
public class MainConfig {

 

总结:

为什么myTypeFilter会被扫描到:

​ 由于我们扫描的基本包是com.ooyhao,所有在这个基本包下面的所有的类都会被扫描到进行过滤,而只有上述结果中的三个是包含"er"的,所有就会被扫描到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值