为了搞清楚springboot的零配置,不得不看@Import
先来写一个简单的代码
这是configuration类
在Appconfig类里,@Import MyClass,这只是一个普通类,并且没有@Component注解
MyClass.java
在main方法里执行完上下文加载后,可以看到,MyClass被初始化了
Main
MyClass的构造方法被打印
那么,可以推测:@Import导入的普通类可以被springbean的生命周期管理
-----------------分割线-----------------
接下来,我们看源码
常规操作,ctrl+左键点它
进入AbstractApplicationContext,看下面截图,
3个方法
这里的3个方法,是看springframework源码的基础入口,
- register(AppConfig.class)会把AppConfig注册到bdMap中
-
会开启12大护法方法,牛逼的不行哦。。。
在AbstractApplicationContext的12大护法方法里,invokeBeanFactoryPostProcessors(beanFactory)方法处理的是BeanDefinition与BeanDefinitionMap的事项
从这里进去看看吧
从这个入口进去看看
一步一步往下走
由于后面的
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
需要2个参数,所以这里先准备一下这2个参数,首先准备第二个参数
参数2的准备
现在准备第一个参数
参数1的准备
参数都准备好了,就可以进入这个方法了
顾名思义,这个方法用来注册BeanDefinition
这里的postProcessor是ConfigurationClassPostProcessor,调用它的postProcessBeanDefinitionRegistry方法来继续处理
继续调用
image.png
image.png
经过一系列不太复杂的流程,得到了configCandidates,这里只有一个自己写的AppConfig
然后,在经过parse.getConfigurationClasses(),得到configClasses
configClasse们
- 拿到了configClasses们,不仅仅只有AppConfig,还有@Import的value类MyClass,为何?可能是因为MyClass也会再次@Import吧。
-
调用reader的loadBeanDefinitions,来load bd鸟
那么,reader又是什么呢?被2挡住了,我再来截个图
reader是ConfigurationClassBeanDefinitionReader
reader有了,configClasses们也有了,就可以放心的调用了
this.reader.loadBeanDefinitions(configClasses);
再跟进来看
一次截2个方法的图
【116】行里有2个类MyClass与AppConfig,可以推测一下,那个会被注册到bdMap里。
好吧,直接看代码第138行,这里有个判断:configClass.isImported(),判断的是,configClass的ImportBy是否为空,如果是空,那么就不是被import进来的,也就不做import处理,那么,这里只有MyClass会进入138行的判断,进而被注册进入bdMap。
然后,我们来做一个【支线任务】,【142】行,会取出configClass的所有beanMethod们,然后把他们都注册进入bdMap里,也就是说@Bean,@Bean,@Bean是在这里被注册进beanDefinitionMap里的。
结束【支线任务】继续往下看,【147】【150】行,是对ImportSelector与ImportBeanDefinitionRegister的处理。
那么总结一下:在ConfigurationClassBeanDefinitionReader类的
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// @Import普通类,这里注册bdMap, 坑:这是把被import的类自己注册到bdMap里
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
// @Bean,这里注册bdMap
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// ImportBeanDefinitionRegister
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// ImportSelector
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
方法里,调用
- registerBeanDefinitionForImportedConfigurationClass(configClass);
- loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
- loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
来处理@Import的3中方式。
结束。。。
网友评论