AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(MaxConfig.class);
这个ioc对象没有指定扫描路径,他是如何工作的呢?
这个构造方法如下:
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
this();
register(componentClasses);
refresh();
}
可以看出这个构造方法,先使用了其他构造方法,其实就是完成扫描器和阅读器的初始化。
继续看就会发现是完成了注解的注册。
this.reader = new AnnotatedBeanDefinitionReader(this);
registerAnnotationConfigProcessors(registry, null);
最后在register(componentClasses);中使用上面的reader,注册就是把扫描到的class存在BeanDefinitionMap里面。
this.reader.register(componentClasses);
这里第一次执行完register,getBeanDefinitionMap里面只有这些,这里还没有扫描其他bean。
当执行到refresh();的时候,会调用doScan()进行扫描
从这个方法进,一步步到scan()方法。
invokeBeanFactoryPostProcessors(beanFactory);
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
112行
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
这个方法调用路径如下 :
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanDefinitionRegistryPostProcessors
上面方法继续调用postProcessor.postProcessBeanDefinitionRegistry(registry);这个方法,实现类如下org.springframework.context.annotation.ConfigurationClassPostProcessor
这个实现里面
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions
这个方法的323行开始解析调用scan方法
// 解析每个 @Configuration
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
这个parse调用170行的parse方法
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)
里面继续调用了parse方法
protected final void parse(@Nullable String className, String beanName) throws IOException {
Assert.notNull(className, "No bean class name for configuration class bean definition");
MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
processConfigurationClass(new ConfigurationClass(reader, beanName), DEFAULT_EXCLUSION_FILTER);
}
通过processConfigurationClass开始正式处理配置类。
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
进这个方法处理各种注解@PropertySource 、@ComponentScan、@Import 、@Bean等
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
点进行看这里的parse方法,可以发现,这个方法的返回值便是doScan方法
这个方法里面,从传的参数componentScan里面找到basePackages,然后传入doScan方法,完成扫描。
String[] basePackagesArray = componentScan.getStringArray("basePackages");
return scanner.doScan(StringUtils.toStringArray(basePackages));
也就是在这里完成bean的扫描,整体流程如上所示。