一、Spring注解之@ComponentScan

Spring注解之@ComponentScan

【1】@ComponentScan注解是什么

@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中

【2】@ComponentScan注解的详细使用

1、创建一个配置类,在配置类上添加 @ComponentScan 注解。该注解默认会扫描该类所在的包下所有的类

package com.zl.springbase.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan
public class MyConfig {
}

我的类结构如下:类MyDao上面添加了@Repository注解

测试程序:

public class TestComponentScan {
    @Test
    public void test1(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println("beanName"+name);
        }
    }
}
/**
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: myConfig
beanName: myDao
*/

2、指定要扫描的包(使用@ComponentScan 的 valule 属性来配置),创建一个controller 包,并在该包下新建一个 MyController 类并添加@Controller注解。

@Configuration
@ComponentScan(value = {"com.zl.springBase.controller"})
public class MyConfig {
}

/**测试结果
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: myConfig
beanName: myController
*/

3、excludeFilters 和 includeFilters 的使用

  • excludeFilters

①使用 excludeFilters 来按照注解类型排除某些包的扫描

@Configuration
@ComponentScan(value = {"com.zl.springBase"},excludeFilters = {
        @Filter(type = FilterType.ANNOTATION,value = {Controller.class})
})
public class MyConfig {
}

/**测试结果
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: myConfig
beanName: myDao
*/

​ excludeFilters 的参数是一个 Filter[] 数组,然后指定 FilterType 的类型为 ANNOTATION,也就是通过注解来过滤,最后的 value 则是Controller 注解类。配置之后,在 spring 扫描的时候,就会跳过 com.zl.springBase包下,所有被 @Controller 注解标注的类。

②使用 excludeFilters 来按照指定类型排除某些包的扫描

@Configuration
@ComponentScan(value = {"com.zl.springBase"},excludeFilters = {
        @Filter(type = FilterType.ASSIGNABLE_TYPE,value = {MyDao.class})
})
public class MyConfig {
}

/**测试结果
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: myConfig
beanName: myController
*/

FilterType 的类型为 ASSIGNABLE_TYPE,就是通过指定类型来过滤,value指定为MyDao,则会过滤掉MyDao这个类。

③使用 excludeFilters 来按照自定义类型排除某些包的扫描

首先创建一个实现 TypeFilter 接口的 CustomTypeFilter 类,并实现其 match 方法。

这里简单对扫描到的类名进行判断,如果类名包含”Co“的就符合条件,也就会注入到容器中。

public class CustomTypeFilter implements TypeFilter {
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取到当前扫描到的类的注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取到当前扫描到的类的信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取到当前扫描到的类的资源
        Resource resource = metadataReader.getResource();
        if (classMetadata.getClassName().contains("Co")) {
            return true;
        }
        return false;
    }
}

MyConfig:

@Configuration
@ComponentScan(value = {"com.zl.springBase"},excludeFilters = {
        @Filter(type = FilterType.CUSTOM,value = {CustomTypeFilter.class})
})
public class MyConfig {
}

/**测试结果
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: myConfig
beanName: myDao
*/

可以看到MyController已经被过滤掉了,myCofig之所以没有被过滤掉是因为它本身是一个配置类,@Configuration注解类里面包含了@Component注解,所以IOC容器启动后MyConfig会被自动加入容器当中。

  • includeFilters

使用 includeFilters 来按照规则只包含某些包的扫描

在创建一个 service 的包,并创建一个 MyService 类,再加上一个 @Service 注解

修改MyConfig类:

@Configuration
@ComponentScan(value = {"com.zl.springBase"},includeFilters = {
        @Filter(type = FilterType.ANNOTATION,value = {Controller.class})
})
public class MyConfig {
}

/**测试结果
beanName: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanName: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanName: org.springframework.context.annotation.internalCommonAnnotationProcessor
beanName: org.springframework.context.event.internalEventListenerProcessor
beanName: org.springframework.context.event.internalEventListenerFactory
beanName: myConfig
beanName: myDao
beanName: myController
beanName: myService
*/

​ 配置里面,应该是只包含 @Controller 注解的类才会被注册到容器中,为什么 @Service,@Repository 注解的类也被注册了呢?这里涉及到 @ComponentScan 的一个 useDefaultFilters 属性的用法,该属性默认值为 true,也就是说 spring 默认会自动发现被 @Component、@Repository、@Service 和 @Controller 标注的类,并注册进容器中。要达到只包含某些包的扫描效果,就必须将这个默认行为给禁用掉(在 @ComponentScan 中将 useDefaultFilters 设为 false 即可)。

posted @ 2019-10-24 18:54  ねぇ  阅读(425)  评论(0编辑  收藏  举报