@ComponentScan用法
ComponentScan为组件扫描,就是根据定义的扫描对应路径,把符合扫描规则的类装配到Spring容器中
@ComponentScan参数说明
@ComponentScan
valeu:只当于扫描的包
excludeFilters: 指定扫描的时候按照某种规则排除那些组件
includeFilters: 指定扫描的时候只需要包含那些组件
FilterType 有五种类型(ANNOTATION:注解类型;ASSIGNABLE_TYPE:ANNOTATION:指定的类型;ASPECTJ:按照Aspectj的表达式,基本上不会用到;REGEX:按照正则表达式;CUSTOM:自定义规则)
实体类
@Component
public class Dog {
public Dog(){
System.out.println("this is Dog");
}
}
@Component
public class Fish {
public Fish(){
System.out.println("this is fish");
}
}
ComponentScan配置扫描类
@ComponentScan(value = "com.honey.badger.nacos.test.config.scan")
public class MainConfig {
@Bean
public Cat cat(){
return new Cat();
}
}
测试类
public class ConfigurationTest {
public static void main(String[] args) {
ApplicationContext anno = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanName = anno.getBeanDefinitionNames();
for (String name : beanName) {
System.out.println(">>>>>: "+name);
}
}
运行结果
>>>>>: 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
>>>>>: mainConfig
>>>>>: dog
>>>>>: fish
>>>>>: cat
在上面的基础上,我们还可以是用ComponentScan的excludeFilters和includeFilters
excludeFilters
添加dogService和fishService实体类
@Service
public class DogService {
public DogService(){
System.out.println("this is DogService");
}
}
@Service
public class DogService {
public DogService(){
System.out.println("this is DogService");
}
}
@Service
public class FishService {
public FishService(){
System.out.println("this is FishService");
}
}
配置实体类
@ComponentScan(
value = "com.honey.badger.nacos.test.config.scan",
excludeFilters = {
//过滤注解
@Filter(type = FilterType.ANNOTATION,classes = {Service.class}),
//过滤某个类
@Filter(type = FilterType.ASSIGNABLE_TYPE,value = {com.honey.badger.nacos.test.config.scan.DogService.class})
},
useDefaultFilters = true
)
public class MainConfig {
@Bean
public Cat cat(){
return new Cat();
}
}
测试类
public class ConfigurationTest {
public static void main(String[] args) {
ApplicationContext anno = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanName = anno.getBeanDefinitionNames();
for (String name : beanName) {
System.out.println(">>>>>: "+name);
}
}
运行结果
>>>>>: 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
>>>>>: mainConfig
>>>>>: dog
>>>>>: fish
>>>>>: cat
这里我们看到dogService和fishService实体并没有加载到我们spring的容器中
includeFilters
@ComponentScan 的一个 useDefaultFilters 属性的用法,该属性默认值为 true,也就是说 spring 默认会自动发现被 @Component、@Repository、@Service 和 @Controller 标注的类,并注册进容器中。要达到只包含某些包的扫描效果,就必须将这个默认行为给禁用掉(在 @ComponentScan 中将 useDefaultFilters 设为 false 即可)
@ComponentScan(
value = "com.honey.badger.nacos.test.config.scan",
includeFilters = {
//过滤注解
@Filter(type = FilterType.ANNOTATION,classes = {Service.class}),
},
useDefaultFilters = false
)
@Configuration
public class MainConfig {
@Bean
public Cat cat(){
return new Cat();
}
}
运行结果
>>>>>: 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
>>>>>: mainConfig
>>>>>: dogService
>>>>>: fishService
>>>>>: cat
这里面Dog和fish类就没有被扫描出来
@ComponentScans
在我们使用多个ComponentScan注解,我们可以使用@ComponentScans注解,从而实现多个扫描的规则,同样也需要加上@Configurtion注解,否则无效
@ComponentScans源码我们看出,他是用有多个ComponentScan组成的
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
配置类
@ComponentScans(value = {
@ComponentScan( value = "com.honey.badger.nacos.test.config"),
@ComponentScan( value = "com.honey.badger.nacos.test.controller")
}
)
@Configuration
public class MainConfig {
@Bean
public Cat cat(){
return new Cat();
}
}
运行结果
>>>>>: mainConfig
>>>>>: cat
>>>>>: dog
>>>>>: dogService
>>>>>: fish
>>>>>: fishService
>>>>>: scopedTarget.helloController
>>>>>: helloController
添加自定义过滤规则
在前面我使用@Filter注解的时候,type属性中FilterTypede的枚举类型:
public enum FilterType {
//注解方式
ANNOTATION,
//指定类型 比如某个类
ASSIGNABLE_TYPE,
//表达式
ASPECTJ,
//正则
REGEX,
//自定义
CUSTOM
}
那我先下面将实现一个的自定义的方式来加载实体类
自定义过滤
public class MyScanFilter implements TypeFilter {
@Override
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("Service")){
System.out.println("className:"+classMetadata.getClassName());
return true;
}
return false;
}
}
配置类
@ComponentScan(
value = "com.honey.badger.nacos.test.config",
includeFilters = { @Filter(type = FilterType.CUSTOM,value = {MyScanFilter.class})},
useDefaultFilters = false)
@Configuration
public class MainConfig {
}
运行结果
>>>>>: mainConfig
>>>>>: dogService
>>>>>: fishService