Spring的版本是5.0.9.release.
1. ClassPathBeanDefinitionScanner
先上一张图,如下图1.
图1
ClassPathBeanDefinitionScanner在哪使用到的呢,看如下List-1,AnnotationConfigApplicationContext的构造方法中,初始化了ClassPathBeanDefinitionScanner,为什么传this进入呢,是因为ClassPathBeanDefinitionScanner的构造方法参数是BeanDefinitionRegistry类型的,ClassPathBeanDefinitionScanner要把扫描到是BeanDefinition注册到BeanDefinitionRegistry中。
List-1
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
private final AnnotatedBeanDefinitionReader reader;
private final ClassPathBeanDefinitionScanner scanner;
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
...
ClassPathBeanDefinitionScanner的最重要的方法是scan(),scan()又调用doScan(),如下List-2
List-2
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);//1
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) {//2
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {//3
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
findCandidateComponents(),做了很多事情,我们来分析下,findCandidateComponents()调用scanCandidateComponents(),scanCandidateComponents()中会在basePackage前面加上"classpaths:",再加上后缀"**/*.class",之后用PathMatchingResourcePatternResolver获取该package下的所有类,并将每个类封装为Resource,如下List-3,之后将每个resource转换为MetadataReader,仔细看下1处isCandidateComponent(metadataReader)的处理,如下List-4,在List-4中,includeFilters默认添加了new AnnotationTypeFilter(Component.class),这意味着isCandidateComponent()方法中调用includeTypeFilter的TypeFilter.match时,只要这个类上标有@Component或者含有@Component的组合注解,那么这个类就会被视为Spring要处理的类来处理,否则不会考虑,includeTypeFilter的TypeFilter.match返回true时,之后调用isConditionMatch(),isConditionMatch方法中又调用conditionEvaluator的shuldSkip方法来判断是否将这个类注册到BeanFactory,conditionEvaluator.shuldSkip()方法处理的是@ConditionalOnXX的情况,比如CondtionalOnBean等,有上面的分析可以看出,先判断类上是否有@Component或者其组合注解,如果有再处理加了@ConditionalOn的情况,如果不符合则这个类不会解析为BeanDefinition,进而不会注册到BeanFactory中。
List-3
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
Resource[] resources = getResourcePatternResolver().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 = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {//1
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);
}
...
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
List-4
private final List<TypeFilter> includeFilters = new LinkedList<>();
private final List<TypeFilter> excludeFilters = new LinkedList<>();
...
protected void registerDefaultFilters() {
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
...
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
...
private boolean isConditionMatch(MetadataReader metadataReader) {
if (this.conditionEvaluator == null) {
this.conditionEvaluator =
new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);
}
return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
}
List-3中,将符合要求的类解析为BeanDefinition,并返回BeanDefiniton集合,回到了List-2中,会遍历得到的BeanDefinition集合,之后先判断是否是AbstractBeanDefinition类型,如果是则调用postProcessBeanDefinition来处理,之后判断是否是AnnotatedBeanDefinition类型,如果是则调用AnnotationConfigUtils.processCommonDefinitionAnnotations处理BeanDefinition,上述分析可知得到的BeanDefinition是ScannedGenericBeanDefinition,所以这个俩个处理方法都会被调用,我们来看下AnnotationConfigUtils.processCommonDefinitionAnnotations,如下List-5:
List-5
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);//1
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
if (metadata.isAnnotated(Primary.class.getName())) {//2
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {//3
abd.setDependsOn(dependsOn.getStringArray("value"));
}
if (abd instanceof AbstractBeanDefinition) {
AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
AnnotationAttributes role = attributesFor(metadata, Role.class);//4
if (role != null) {
absBd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);//5
if (description != null) {
absBd.setDescription(description.getString("value"));
}
}
}
- 判断类上是否有Lazy注解,如果是则取出value的值,设置到BeanDefinition中。
- 判断类上是否有Primary注解,如果是则给BeanDefinition的Primary设置为true。
- 判断类上是否有DependsOn注解,如果是则获取值并设置到BeanDefinition中。
List-5中处理完了后,回到List-2,方法registerBeanDefinition将这个BeanDefinition注册到Spring容器中。
2. 拓展——mybatis扫描类
使用Spring-mybatis来集成mybatis时,MapperScannerConfigurer中使用ClassPathMapperScanner来扫描类,解析为BeanDefinition后,将BeanDefinition的beanClass类型设置为MapperFactoryBean——FactoryBean类型。