springboot自动配置原理,到底怎么实现的自动配置,怎么加载的META-INF.spring.factories文件。仿真一下程序,走起。
1.主启动类调用run方法
2.createApplicationContext方法
见名知意,这就是创建容器的方法。
进到方法,会执行到这一步 web项目的话,当前容器类型为AnnotationConfigServletWebServerApplicationContext类型。然后调用BeanUtils工具类初始化这个容器。
进到BeanUtils类的instantiateClass方法,会继续执行重载的instantiateClass方法
然后会执行到这一步 newInstance 肯定是创建对象了。
3.newInstance方法
可以看到已经进入了当前ioc容器的构造方法,执行这个构造方法前会先执行父类的构造方法。
仿真step into看下
继续step into
再继续,创建了默认的bean工厂。
然后一路执行,回到AnnotationConfigServletWebServerApplicationContext类,可以看到容器中的bean工厂已经创建,就是DefaultListableBeanFactory。
继续执行,这两步的功能在spring专栏中IOC容器启动过程里有介绍,第一个是向容器中注册几个系统级的bean,完成@Configuration、@Import、@ComponentScan、@Component、@Bean、@Autowired等注解的支持。第二个是完成@ComponentScan注解的支持。其中ConfigurationClassPostProcessor最重要,导入其他组件就靠这个。
4.prepareContext方法
继续执行run方法,prepareContext方法将主启动类也加到了beanDefinitionMap中。
5.refreshContext方法
最关键的方法,就是经过这一步,导入了所有spring容器管理的bean。可以看到,也是调用的父类的refresh方法。
直接看这个方法 执行factory processors 将bean注册到容器中
BeanFactoryPostProcessor 有两种获取方法
第一种,可能 BeanFactoryPostProcessor 已经实例化成了 bean,那么它存放在 context 的 beanFactoryPostProcessors属性中;
第二种,BeanFactoryPostProcessor还没有实例化,目前仅仅之是个“蓝图”(beanDefinition),那么它存放在 context 的 beanFactory 属性的 beanDefinitionMap 属性中。
继续进入invokeBeanFactoryPostProcessors方法
这是第一种获取也就是这三个
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
// 遍历已经注册的 beanFactoryPostProcessor。
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
//如果是BeanDefinitionRegistryPostProcessor类型的就执行
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
//不是BeanDefinitionRegistryPostProcessor类型的就存取来
else {
regularPostProcessors.add(postProcessor);
}
}
这是第二种获取方法,也就是beanDefinition中存的processor,主要是这个类
先获取到最一开始注册进容器的internalConfigurationAnnotationProcessor。然后加到currentRegistryProcessors中。这里需要的类型是BeanDefinitionRegistryPostProcessor类型的,而我们想要的ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,所以可以获取到
此处的internalConfigurationAnnotationProcessor是map中的key,获取到的value是ConfigurationClassPostProcessor。
6.invokeBeanDefinitionRegistryPostProcessors方法
获取到所有标注了@configuration的类, 这里是是获取所有满足condition条件的自动配置类。
创建配置类解析器 parser,后面就是使用它 寻找 并 解析 所有的配置类。
loadBeanDefinitions加载所有的bean,可以看出经过这个方法,就把很多bean加载进来了。
loadBeanDefinitions方法,遍历标注了@configuration的类,将里面的bean加载进容器
loadBeanDefinitionsForConfigurationClass方法
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;
}
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
看下50个自动配置类
就是加载这些配置类中的bean到容器中。
到这里有个疑问,到底是怎么找到这些类的?正常想法是主启动类加了@SpringBootApplication注解。然后这个注解有@EnableAutoConfiguration注解,然后@EnableAutoConfiguration注解有@AutoConfigurationPackage注解和@Import(AutoConfigurationImportSelector.class),AutoConfigurationImportSelector类中自动配置了路径 :“META-INF.spring.factories”,所以应该是主启动类加进容器后,想要的两个类AutoConfigurationPackages和AutoConfigurationImportSelector也会加到容器中,而且主启动类肯定是要先加载的。
验证:
目前容器中有这几个组件,当前的class是启动类
代码执行一步,发现只多了一个,AutoConfigurationImportSelector并没有自动导入,所以肯定是在更早的时候导入的。
仿真查找,发现在loadBeanDefinitions之前的parser.parse(candidates)方法完成的查找及过滤。
回过头查看这个方法。
继续进入
继续
继续。。
继续 加油
看到这终于有点眼熟了,loadFactoryNames是加载META-INF.spring.factories
从META-INF.spring.factories加载EnableAutoConfiguration类型的组件
加载了124个
过滤之后还有24个
最后返回的是50个,这里返回24个,为啥呢,搞了半天没搞明白 难受啊
看下是怎么加载的吧
先从缓存获取,有的话直接返回。这里是可以从缓存拿到的,在SpringApplicaition构造函数中。
获取初始化器的时候,就会将META-INF.spring.factories里边的内容全部加载然后缓存。
到现在为止搞懂了这50个配置类是怎么来的了,parser.parse方法,去spring.factories文件中找,然后过滤。然后返回
不过已经忘了最初是要干什么来着。。。
进到了AbstractApplicationContext类的refresh方法,也就是本文的第五步,这个方法是加载组件的。然后这个方法中有个关键方法invokeBeanFactoryPostProcessors方法。然后这个方法中有个关键的方法
invokeBeanDefinitionRegistryPostProcessors方法,也就是本文的第六步,看名字就知道,执行BeanDefinition注册工具,执行完它肯定就将所有组件导入了。该方法中继续执行processConfigBeanDefinitions(registry);就是在这个方法中调用parser.parse方法,获取到50个自动配置组件,然后调用loadBeanDefinitions加载配置类中导入的组件。
这样,就基本搞清楚了,springboot run方法执行过程中导入自动配置组件的过程。
refresh方法执行完,run方法也就差不多了。