日常項目中,使用注解@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注解分析完成了,后續接着優化~