日常项目中,使用注解@EnableAspectJAutoProxy @EnableAsync
这里面涉及对@Import注解支撑的底层原理:ConfigurationClassPostProcessor 这个类,说到这个类,我们要先从SpringBoot启动流程说起。
首先,看springboot启动流程中的一步:
SpringApplication对象的run方法,创建上下文context = createApplicationContext(); 这一步,会创建AnnotationConfigServletWebServerApplicationContext对象:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS); (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
类图关系如下:
AnnotationConfigServletWebServerApplicationContext类有两个重要的属性:private final AnnotatedBeanDefinitionReader reader; private final ClassPathBeanDefinitionScanner scanner;
创建AnnotationConfigServletWebServerApplicationContext对象时, 调用构造方法,会初始化该对象的上面两个属性。见:
public AnnotationConfigServletWebServerApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
在new AnnotatedBeanDefinitionReader(this)对象时,里面会涉及AnnotatedBeanDefinitionReader构造函数AnnotatedBeanDefinitionReader构造函数AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);其中会对spring内置管理的几个特殊类封装成BeanDefinition,缓存到map中;其中就包含对ConfigurationClassPostProcessor的处理:该类实现了BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor,重写了 postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)方法与postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)方法
然后,看springboot启动流程中的另外一步:
SpringApplication对象的run方法,加载spring容器refreshContext(context);定位到AbstractApplicationContext类的refresh()方法,方法内部流程中有一步invokeBeanFactoryPostProcessors(beanFactory);
内部通过 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); 其中最重要的一步是:String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); 遍历 然后currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));这里会对所有BeanDefinitionRegistryPostProcessor的实现类进行getBean实例化的操作(ConfigurationClassPostProcessor在这里得到实例化)
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); 遍历调用每一个BeanDefinitionRegistryPostProcessor的实现类的postProcessBeanDefinitionRegistry方法,所以ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法会得到调用
下面看ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法:
processConfigBeanDefinitions(registry); 内部会构建一个ConfigurationClassParser对象 Parse each @Configuration class 通过parser.parse(candidates);定位到processConfigurationClass(ConfigurationClass configClass);再到doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) ;这里会处理 @PropertySource, @ComponentScan,@Import,@ImportResource,@Bean 及 Process default methods on interfaces;// Process any @Import annotations ---> processImports(configClass, sourceClass, getImports(sourceClass), true); 该方法里会有对@Import注解3种方式ImportSelector实现类和ImportBeanDefinitionRegistrar实现类以及未实现这些接口的类的处理;
if(实现ImportBeanDefinitionRegistrar){
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());后面的ConfigurationClassPostProcessoorl类的processConfigBeanDefinitions方法中的this.reader.loadBeanDefinitions(configClasses)会调用这些ImportBeanDefinitionRegistrar实现类的registerBeanDefinitions方法
}else if(实现ImportSelector){
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); // 第1步
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false); // 第2步
这里涉及到递归调用,第一次进来时,走到第1步,拿到importClassNames执行第2步时,会跳转到处理没有实现ImportBeanDefinitionRegistrar和ImportSelector这些接口的普通bean了
}else{
//对没有实现ImportBeanDefinitionRegistrar和ImportSelector这些接口的普通bean了
processConfigurationClass(candidate.asConfigClass(configClass));
}
processImports方法执行完毕,Import注解导入的bean都被保存在ConfigurationClassParser实例中,回到processConfigBeanDefinitions(registry),parse之后,this.reader.loadBeanDefinitions(configClasses);// parse那里准备好了bean信息,这里是真正的处理;ConfigurationClassBeanDefinitionReader类中是对每个配置类逐个执行loadBeanDefinitionsForConfigurationClass方法,
// 普通的类,通过下面的方法将bean定义注册在spring环境
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 实现了ImportBeanDefinitionRegistrar接口的实例,会执行
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
到此,@Import注解分析完成了,后续接着优化~