springboot创建IOC容器时导入自动配置组件过程

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方法也就差不多了。

猜你喜欢

转载自blog.csdn.net/weixin_46666822/article/details/124813791