@Import底层实现原理

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

 

posted @ 2021-01-03 16:08  艳阳下的小菜园  阅读(944)  评论(0编辑  收藏  举报