此注解是springboot自动注入的关键注解,所以拿出来单独分析一下。
启动类的run方法跟进去最终找到refresh方法;
这里直接看这个org.springframework.context.support.AbstractApplicationContext#refresh方法即可,它下面有一个方法
invokeBeanFactoryPostProcessors(beanFactory)
此处, 最终调用的是:
org.springframework.context.support.PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors方法;
在这里就不做详细的每一步分析了,直接找起作用的代码了。
它下面有一段如下代码:
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
断点可以看到
在加上代码的注释,此时第一步调用了获取实现BeanDefinitionRegistryPostProcessor的接口的类的方法,可以看到此时只有一个类,即ConfigurationClassPostProcessor类,它是由容器初始化的时候指定加载的bean定义,用来扫描springboot注解配置的相关属性类;
所以此时就会调用其的processConfigBeanDefinitions方法,此方法中有一个
parser.parse(candidates)
最终调用的方法中会有如下代码
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true)
可以看到,到此处的时候,才会去加载@Import注解,但在此之前程序会扫描@Component、@PropertySources@ComponentScans注解;
此时,读取到相应的实现import引入的类的selectImports方法,即可执行相关的配置属性;在执行的时候有一个判断:
if (candidate.isAssignable(ImportSelector.class)) {
}else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
}
即使用Import注解时,其类必须实现ImportSelector接口或者ImportBeanDefinitionRegistrar接口;
然后调用其selectImports方法或者registerBeanDefinitions方法,这里ImportSelector还有一个子接口即:DeferredImportSelector接口
那么在这个三者之间存在什么关系?
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
如果实现了DeferredImportSelector接口,它会将其放入一个DeferredImportSelectorHandler中,不会立马执行;而如果是ImportSelector接口,则会直接调用其方法。如果是ImportBeanDefinitionRegistrar接口,则会添加到ConfigurationClass#importBeanDefinitionRegistrars属性中,他是一个map。
所以,ImportSelector接口会直接执行方法,其他两种都会延迟执行加载,那么延迟到什么时候呢?
1)对于DeferredImportSelector接口,则是parse方法的最后一步:
this.deferredImportSelectorHandler.process()
此时才会去执行实现ImportBeanDefinitionRegistrar接口的方法;
此时要注意,ImportBeanDefinitionRegistrar接口内部有一个Group接口,当getImportGroup方法不返回null时,此时就不会执行其selectImports接口了,此时会调用Group下的process方法;此处在后面会使用到;
ImportSelector与DeferredImportSelector的区别,就是selectImports方法执行时机有差别,在DeferredImportSelector之前会对@ImportResource、@Bean这些注解进行处理。
2)对于ImportBeanDefinitionRegistrar接口,
在上面的parse方法执行完之后,会有如下方法:
this.reader.loadBeanDefinitions(configClasses)
此时会执行ImportBeanDefinitionRegistrar接口的方法;
所以最终的执行时机为:
ImportSelector接口的优先级高于DeferredImportSelector接口的执行时机;
DeferredImportSelector接口的优先级高于ImportBeanDefinitionRegistrar接口的执行时机。