0
点赞
收藏
分享

微信扫一扫

【Spring6源码・IOC】BeanDefinition的加载

转角一扇门 2023-01-13 阅读 127

哎呀,又是午夜时分,又是一个失眠的夜晚,和去年一样,记得去年今日,也是睡不着觉,就注册了csdn的账号,开始写东西,csdn真是深夜最好的安魂剂。

Spring都发布了6.0,这不赶紧看看源码,咱们来一起学习学习,废话不多说了,开始吧。

文章目录

IOC核心流程简介

环境:Spring6、SpringBoot3.0、JDK17

IOC是一个容器,对象的创建、使用和销毁都是由IOC容器来管理。

小白可以先看这篇:《五分钟带你速通Spring IOC》


所以,我们先从第一步开始:BeanDefinition的封装

BeanDefinition的设计思想

BeanDefinition是存储Bean的元信息,包括Bean本身的信息,以及Bean注解信息。这个信息就是从我们的配置文件以及配置类等加载以及进行一系列处理而来。

首先会构建一个解析器去扫描所有的@Controller、@Service、@Repository、@Component、@Configuration类

通过这三种方法加载 BeanDefinition,并将他们放到缓存beanDefinitionMap中。

那么是如何解析这些注解的?时机是什么?我们来一起看一看

解析@ComponentScan

以SpringBoot的启动来说,我们通过SpringApplication#run,最终调用AbstractApplicationContext 的 refresh() 方法。

在这里插入图片描述
invokeBeanFactoryPostProcessors这个方法就是用来加载BeanDefinition。

最后进入到ConfigurationClassPostProcessor 的 processConfigBeanDefinitions 方法
在这里插入图片描述
这里是找到我们启动类的BeanDefinition,然后构建了一个ConfigurationClassParser解析器,去扫描我们加上注解的类,并加载为 BeanDefinition。

在这里插入图片描述

进入 parse 方法,最终我们会来到,老套路了,方法前面加do的,都是比较核心的方法,包括后面扫描的时候有一个doScan。
在这里插入图片描述
进入到 ConfigurationClassParser 的 doProcessConfigurationClass 方法
在这里插入图片描述
这里可以看到,这个又有一个解析器ComponentScanAnnotationParser,它是用来处理@Controller、@Service、@Repository、@Component、@Configuration这些注解的。

我们来看看它做了什么事。

在这里插入图片描述

首先构建了一个ClassPathBeanDefinitionScanner对象,然后对它进行一些set操作,最后进入核心方法doScan中。

在这里插入图片描述
首先findCandidateComponents(basePackage) 方法会扫描启动类所在的包(默认),找到符合条件的类(被@ComponentScan扫描到的,以及@Configuration),最后在通过registerBeanDefinition(definitionHolder, this.registry)方法将BeanDefinition注册金beanDefinitionMap中。

我们可以细讲一下这两个地方,首先看如何筛选类的。

findCandidateComponents(basePackage) 方法最后进入下面这个核心方法

在这里插入图片描述
首先通过getResourcePatternResolver().getResources(packageSearchPath)加载出所有的类并封装成Resource数组,然后在通过isCandidateComponent(metadataReader)筛选出符合的类,最后构建成BeanDefinition类,添加到set集合中,最后返回。

registerBeanDefinition(definitionHolder, this.registry)方法呢,就比较直接了,如果在缓存中获取不到就直接加锁,然后添进缓存中。
在这里插入图片描述
到此,@ComponentScan 就扫描完成了,BeanDefinition 也加载完成了。

解析@Bean

大多时候,@Bean是和@Configuration一起使用的,由上文可知,@Configuration相关类在ComponentScanAnnotationParser处就会被解析到。

如图上面这个方法是上文一直在讲解的(讲@ComponentScan扫描到的类加入缓存中),下面这个就是真正解析@Bean和@Import并将其加入缓存的方法。

在这里插入图片描述

我们来看看吧,因为一个配置类可能不止一个@Bean,所以循环对每一个@Bean处理

在这里插入图片描述
最后通过this.registry.registerBeanDefinition(beanName, beanDefToRegister)将@Bean相关BeanDefinition添加进beanDefinitionMap中。

解析@Import

其实@Import更为简单一些,这里优先判断其是否为@Import。
在这里插入图片描述
在parser.parse 方法中,先将 类转化为一个 ConfigurationClass 类,设置到它的 importedBy 属性中。然后在之后的 loadBeanDefinitions 方法中,判断 ConfigurationClass 的 importedBy 属性是否为空,如果不为空,说明是需要加载的,将它加载为 BeanDefinition,最后registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass)方法中的this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition())将BeanDefinition添加进IOC容器中。

在这里插入图片描述

完事了。等下一章吧

举报

相关推荐

0 条评论