调用 ComponentScan 的地方如下所示:
Set componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
protected final ConfigurationClassParser.SourceClass doProcessConfigurationClass(ConfigurationClass configClass, ConfigurationClassParser.SourceClass sourceClass) throws IOException {
this.processMemberClasses(configClass, sourceClass);
Iterator var3 = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, PropertySource.class).iterator();
AnnotationAttributes importResource;
while(var3.hasNext()) {
importResource = (AnnotationAttributes)var3.next();
if (this.environment instanceof ConfigurableEnvironment) {
this.processPropertySource(importResource);
} else {
this.logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment");
}
}
//!!!
//看这里!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
////!!!
Set componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
Iterator var13 = componentScans.iterator();
while(var13.hasNext()) {
AnnotationAttributes componentScan = (AnnotationAttributes)var13.next();
Set scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
Iterator var7 = scannedBeanDefinitions.iterator();
while(var7.hasNext()) {
BeanDefinitionHolder holder = (BeanDefinitionHolder)var7.next();
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
this.parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
this.processImports(configClass, sourceClass, this.getImports(sourceClass), true);
if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
String[] resources = importResource.getStringArray("locations");
Class extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
String[] var20 = resources;
int var21 = resources.length;
for(int var22 = 0; var22 < var21; ++var22) {
String resource = var20[var22];
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
Set beanMethods = this.retrieveBeanMethodMetadata(sourceClass);
Iterator var16 = beanMethods.iterator();
while(var16.hasNext()) {
MethodMetadata methodMetadata = (MethodMetadata)var16.next();
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
this.processInterfaces(configClass, sourceClass);
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
return sourceClass.getSuperClass();
}
}
return null;
}
我们先来看看代码如何从最开始流程一步一步调用到这个函数的:
要应用 注解需要这么一行代码:
ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
进入到 AnnotationConfigApplicationContext:
看过源码的应该很熟悉这个,基本上是第一步:
然后一步一步调用:
整个 bean 实例化初始化的流程:
invokeBeanFactoryPostProcessors:
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry):
代码太长截图一页显示不出来,只贴出关键部分:
继续
终于到了关键的地方:
注意这一行:
ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);
所有配置类注解都在这里创建。
创建的时候:
this.componentScanParser = new ComponentScanAnnotationParser(environment, resourceLoader, componentScanBeanNameGenerator, registry);
继续看
parser.parse(candidates);
这就回到了我们最开始的地方:
所有扫描出来的 bean 都在这里解析
主业务流程都在这个 parse 中 doscan 函数中:
扫描所有的配置类:
这个函数里,做class path 的拼接,读取 class 信息
下面这个函数中判断是否实例化,isCandidateComponent 处理中还有 filter 的相关处理。
if (this.isCandidateComponent((AnnotatedBeanDefinition)sbd)) {
if (debugEnabled) {
this.logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}