目录
1. 说明
2. @ComponentScan注解属性
3. @ComponentScan过滤规则说明
4. 自定义扫描过滤规则
5. @ComponentScan原理分析
6. @ComponentScans
与ComponentScan注解相对应的XML配置就是
XML的配置方式如下:
@ComponentScan有如下属性:
value:指定要扫描的package;
includeFilters=Filter[]:指定只包含的组件
excludeFilters=Filter[]:指定需要排除的组件;
useDefaultFilters=true/false:指定是否需要使用Spring默认的扫描规则:被@Component, @Repository, @Service, @Controller或者已经声明过@Component自定义注解标记的组件;在过滤规则Filter中:
FilterType:指定过滤规则,支持的过滤规则有
ANNOTATION:按照注解规则,过滤被指定注解标记的类;
ASSIGNABLE_TYPE:按照给定的类型;
ASPECTJ:按照ASPECTJ表达式;
REGEX:按照正则表达式
CUSTOM:自定义规则;
value:指定在该规则下过滤的表达式;
规则表达式说明
1. 扫描指定类文件
@ComponentScan(basePackageClasses = Person.class)
2. 扫描指定包,使用默认扫描规则,即被@Component, @Repository, @Service, @Controller或者已经声明过@Component自定义注解标记的组件;
@ComponentScan(value = "com.yibai")
3. 扫描指定包,加载被@Component注解标记的组件和默认规则的扫描(因为useDefaultFilters默认为true)
@ComponentScan(value = "com.yibai", includeFilters = { @Filter(type = FilterType.ANNOTATION, value = Component.class) })
4. 扫描指定包,只加载Person类型的组件
@ComponentScan(value = "com.yibai", includeFilters = { @Filter(type = FilterType.ASSIGNABLE_TYPE, value = Person.class) }, useDefaultFilters = false)
5. 扫描指定包,过滤掉被@Component标记的组件
@ComponentScan(value = "com.yibai", excludeFilters = { @Filter(type = FilterType.ANNOTATION, value = Component.class) })
6. 扫描指定包,自定义过滤规则
@ComponentScan(value = "com.yibai", includeFilters = { @Filter(type = FilterType.CUSTOM, value = ColorBeanLoadFilter.class) }, useDefaultFilters = true)
自定义规则实现类ColorBeanLoadFilter
/**
* Project Name:yibai-spring-annotation
* File Name:ColorBeanLoadFIlter.java
* Package Name:com.yibai.spring.annotation.filter
* Date:2019年1月5日下午12:15:54
* Copyright (c) 2019, www.windo-soft.com All Rights Reserved.
*
*/
package com.yibai.spring.annotation.filter;
import java.io.IOException;
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 com.yibai.spring.annotation.bean.color.Color;
public class ColorBeanLoadFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// 当前被扫描类的注解信息
@SuppressWarnings("unused")
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 当前被扫描类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 当前被扫描类资源信息
@SuppressWarnings("unused")
Resource resource = metadataReader.getResource();
try {
String className = classMetadata.getClassName();
Class> forName = Class.forName(className);
if (Color.class.isAssignableFrom(forName)) {
// 如果是Color的子类,就加载到IOC容器
return true;
}
} catch (ClassNotFoundException e) {
// e.printStackTrace();
}
return false;
}
}
@ComponentScan的解析器是org.springframework.context.annotation.ComponentScanAnnotationParser;
useDefaultFilters = true指定的规则过滤器是 org.springframework.core.type.filter.AnnotationTypeFilter;’
public Set parse(AnnotationAttributes componentScan, final String declaringClass) {
/** componentScan为@ComponentScan的注解信息:
{value=[com.yibai.spring.annotation], basePackages=[com.yibai.spring.annotation], lazyInit=false, scopeResolver=class org.springframework.context.annotation.AnnotationScopeMetadataResolver, scopedProxy=DEFAULT, nameGenerator=interface org.springframework.beans.factory.support.BeanNameGenerator, useDefaultFilters=true, basePackageClasses=[], includeFilters=[], resourcePattern=**/*.class, excludeFilters=[]}
*/
Assert.state(this.environment != null, "Environment must not be null");
Assert.state(this.resourceLoader != null, "ResourceLoader must not be null");
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
//....
//..
//.
//中间代码省略了,大概做的事情就是创建包扫描器,然后被@CompontentScan注解设置的属性都设置搭配扫描器中,然后准备扫描
// 经过一些列的scanner的属性设置,进入扫描流程
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
然后进入org.springframework.context.annotation.ClassPathBeanDefinitionScanner.doScan(String...) 进行扫描,并生成组件定义信息;
protected Set doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set beanDefinitions = new LinkedHashSet();
for (String basePackage : basePackages) {
// 根据扫描规则扫描出符合条件的组件
Set candidates = findCandidateComponents(basePackage);
//下面就是将扫描出的组件实加载到IOC容器中;
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
通过org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.findCandidateComponents(String)找出符合条件的组件
public Set findCandidateComponents(String basePackage) {
Set candidates = new LinkedHashSet();
try {
//classpath*:com/yibai/spring/annotation/**/*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//resources 就是指定包下的所有类
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
//遍历所有类,判断是否符合规则
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
//注意这里,根据过滤规则进行判断
if (isCandidateComponent(metadataReader)) {
//如果符合条件,这将组件让如待返回的集合中去;
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setResource(resource);
sbd.setSource(resource);
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
通过org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider.isCandidateComponent(MetadataReader)方法,根据过滤器规则判断类是否满足条件
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//是否满足排除的条件
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
}
// 是否满足包含的条件
for (TypeFilter tf : this.includeFilters) {
//判断是否过滤器满足
if (tf.match(metadataReader, this.metadataReaderFactory)) {
// 判断是否条件满足
return isConditionMatch(metadataReader);
}
}
return false;
}
当断点到自定义过滤类里面的时候,调用栈如下
可以一次声明多个@ComponentScan
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class) //指定ComponentScan可以被ComponentScans作为数组使用
public @interface ComponentScan {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
@ComponentScans(value = { @ComponentScan(value = "com.yibai.spring.annotation"),
@ComponentScan(value = "com.yibai.spring.annotation", includeFilters = {
@Filter(type = FilterType.CUSTOM, value = ColorBeanLoadFilter.class) }) })
public class MainConfig {
@Bean(name = "pers", initMethod = "init", destroyMethod = "destory")
public Person person() {
return new Person();
}
}