ComponentScan 注解
- @ComponentScan 用法 1:
package com.niewj.config;
import com.niewj.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@Configuration
@ComponentScan("com.niewj")
public class MainConfig {
@Bean
public Person person() {return new Person("張三", 22);
}
}
(0). 惯例: @ComponentScan(value="com.niewj")
(1). FilterType.ANNOTATION
只排除注解 value
+ excludeFilters
@ComponentScan( // 只排除:
value = "com.niewj",
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)}
)
(2).FilterType.ANNOTATION
只过滤注解: 须要加上 value
+ useDefaultFilters=false
+ includeFilters
@ComponentScan( // 只蕴含: 必须要写 useDefaultFilters 否则不失效
value = "com.niewj",
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)}
)
(3). FilterType.ASSIGNABLE_TYPE
: 制订具体的类型, includeFilters 和 excludeFilters 自身就是个数组!
@ComponentScan( // 只蕴含: 必须要写 useDefaultFilters 否则不失效
value = "com.niewj",
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = BookService.class)
}
)
- 自定义 TypeFilter @ComponentScan 用法:
@Test
public void testTypeFilter() {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
Arrays.stream(ctx.getBeanDefinitionNames()).forEach(System.out::println);
}
输入如下:
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
mainConfig
bookController
person
MainConfig.java:
package com.niewj.config;
import com.niewj.bean.Person;
import com.niewj.util.MyComponentScanTypeFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
@Configuration
@ComponentScan(value = "com.niewj",
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyComponentScanTypeFilter.class)
}
)
public class MainConfig {
@Bean
public Person person() {return new Person("張三", 22);
}
}
次要看 MyComponentScanTypeFilter 的类申明: 它的判断逻辑是满足一下两点, 则匹配!
- 如果类有注解 @Controller
- 如果类是 BaseController 的子类
package com.niewj.util;
import com.niewj.controller.BaseController;
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;
/**
* 自定义 ComponentScan 形式:
*/
public class MyComponentScanTypeFilter implements TypeFilter {
/**
* 此处的判断逻辑是:
* 如果
* 1. 类是 BaseController 的子类
* 2. && 注解蕴含 @Controller, 则匹配!
*
* @param metadataReader 获取到的以后类的注解信息
* @param metadataReaderFactory 可获取到其余类信息的工厂
* @return
* @throws IOException
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 1. 获取以后类的注解信息
AnnotationMetadata annoMetadata = metadataReader.getAnnotationMetadata();
// 2. 获取以后正在扫描的类信息:
ClassMetadata classMetadata = metadataReader.getClassMetadata();
if (isBaseController(classMetadata) && hasControllerAnnotation(annoMetadata)) {return true;}
return false;
}
/**
* 条件 1: 正在扫描的类 是不是 BaseController 的子类
*
* @param classMetadata
* @return
*/
private boolean isBaseController(ClassMetadata classMetadata) {
// 3. 正在扫描的类名称
String className = classMetadata.getClassName();
// 4. 正在扫描的类的父类, 格局: BookController->com.niewj.controller.BaseController
String superClassName = classMetadata.getSuperClassName();
return superClassName.contains(BaseController.class.getSimpleName());
}
/**
* 判断注解中有无 Controller "org.springframework.stereotype.Controller"
*
* @param annotationMetadata
* @return
*/
private boolean hasControllerAnnotation(AnnotationMetadata annotationMetadata) {return annotationMetadata.getAnnotationTypes().stream().anyMatch(e -> e.equals("org.springframework.stereotype.Controller"));
}
}
小结: ComponentScan 扫描大抵罕用有这么几类:
1. 一般 @ComponentScan(value=”com.niewj”)
2. 注解过滤排除: @ComponentScan(value=”com.niewj”, excludeFilters={filter1, filter2,…})
3. 注解过滤蕴含: @ComponentScan(value=”com.niewj”, includeFilters={filter1, filter2, …})
其中的 Filter 蕴含
(1). 注解过滤匹配: type = FilterType.ANNOTATION
(2). 指定的类名比配: type=FilterType.ASSIGNABLE_TYPE
(3). 自定义类型匹配: type=FilterType.CUSTOM 如示例中的:
MyComponentScanTypeFilter implements `TypeFilter`
(4). type=FilterType.ASPECTJ (不罕用)
(5). 正则匹配 type=FilterType.REGEX (不罕用)