【源码解析】SpringIOC

举报
小明的混沌之路 发表于 2022/07/31 14:43:12 2022/07/31
【摘要】 SpringIOC有两个核心思想就是IOC控制反转和DI依赖注入,IOC控制反转的基本思想是,将原来的对象从使用者来进行控制

前言:📫 作者简介:小明java问道之路,专注于研究计算机底层,就职于金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的设计和架构📫 

🏆 Java领域优质创作者、阿里云专家博主、华为云专家🏆

🔥 如果此文还不错的话,还请👍关注点赞收藏三连支持👍一下博主哦

本文导读

SpringIOC有两个核心思想就是IOC控制反转和DI依赖注入,IOC 控制反转的基本思想是,将原来的对象控制从使用者,有了spring之后可以把整个对象交给spring来帮我们进行管理,DI 依赖注入,就是把对应的属性的值注入到具体的对象中。spring提供<bean/>标签和@Autowired和@Resource注解等方式注入,注入方式本质上是AbstractAutowireCapableBeanFactory的populateBean() 方法先从beanDefinition 中取得设置的property值,例如autowireByName方法会根据bean的名字注入;autowireByType方法根据bean的类型注入,完成属性值的注入(涉及bean初始化过程)。对象会存储在map结构中,在spring使用Map结构的singletonObjects存放完整的bean对象(涉及三级缓存和循环依赖)。整个bean的生命周期,从创建到使用到销毁的过程全部都是由容器来管理(涉及bean的生命周期)。

一、bean生命周期

        IOC核心流程重点关注有 bean生命周期,主要分为初始化和销毁
1、在正式进入容器的刷新前,会进行一些前置操作。主要为了(1)确认要使用的容器,通常使用的是:XmlWebApplicationContext,如果是用 Spring Boot,一般是AnnotationConfigApplicationContext,但其实都差别不大,最终都会继承AbstractApplicationContext,核心逻辑也都是在 AbstractApplicationContext 中实现。(2)还有一个目的是提供一个给开发者初始化 ApplicationContext 的机会。
————————————初始化过程————————————

2、初始化 BeanFactory默认为 DefaultListableBeanFactory 、它会加载 Bean 定义,向bean工厂中设置一些参数;例如:BeanNameAware.setBeanName() 在创建此bean的bean工厂中设置bean的名称和BeanClassLoaderAware.setBeanClassLoader()setBeanFactory() : 回调提供了自己的bean实例工厂等,然后将 beanName、BeanDefinition 放到 BeanFactory 的缓存中,用于后续创建 Bean 实例时使用。

3、触发 BeanFactoryPostProcessor;BeanFactoryPostProcessor 接口是 Spring 初始化 BeanFactory 时对外暴露的扩展点,Spring IOC 容器允许 BeanFactoryPostProcessor 在容器实例化任何 bean 之前读取 bean 的定义,并可以修改它。BeanDefinitionRegistryPostProcessor 继承自 BeanFactoryPostProcessor,比 BeanFactoryPostProcessor 具有更高的优先级;另外,Mybatis 中的 MapperScannerConfigurer 是一个典型的 BeanDefinitionRegistryPostProcessor 的扩展使用;

我们也可以implements BeanFactoryPostProcessor 再使用@Component注册到Spring,实现自己的 postProcessBeanFactory() 逻辑。

4、注册所有的 BeanPostProcessor,将所有实现了 BeanPostProcessor 接口的类加载到 BeanFactory 中。BeanPostProcessor 接口是 Spring 初始化 bean 时对外暴露的扩展点,方便后续对bean对象完成具体的扩展功能;

我们也可以implements BeanPostProcessor再使用@Component注册到Spring,实现自己的postProcessBeforeInitialization()和postProcessAfterInitialization()

5、实例化所有剩余的非懒加载单例 bean,将所有BeanDefinition对象实例化成具体的bean对象。(1)首先会遍历所有被加载到缓存中的 beanName,触发所有剩余的非懒加载单例 bean 的实例化。(2)同时通过 beanName 尝试从缓存中获取,如果存在则跳过实例化过程;否则,进行 bean 的实例化。(3)根据 BeanDefinition使用构造函数创建 bean 实例 或者 进行 bean 实例属性填充。最后执行 bean 实例的初始化。

6、生成完整的bean对象,通过getBean方法可以直接获取。

————————————销毁————————————

7、在BeanFactory 关闭的时候,Bean的生命周期会调用如下方法:(1)DestructionAwareBeanPostProcessor.postProcessBeforeDestruction(): 在销毁之前将此BeanPostProcessor 应用于给定的bean实例。能够调用自定义回调,像是DisposableBean 的销毁和自定义销毁方法,这个回调仅仅适用于工厂中的单例bean(包括内部bean)(2)实现了自定义的 destory() 方法

二、重点关注的类

        这里面主要关注对象有,bean 是一个由Spring IOC容器实例化,组装和管理的对象;
BeanDefinition 是bean的定义,用来存储bean的所有属性方法定义。ApplicationContext BeanFactory  的子接口,在 BeanFactory 的基础上构建,是相对比较高级的IOC容器实现。包含 BeanFactory 的所有功能,还提供了其他高级的特性,比如:事件发布、国际化信息支持、统一资源加载策略等。正常情况下,我们都是使用的 ApplicationContext。还有BeanFactory是基础类型 IOC 容器,提供完整的 IOC 服务支持。FactoryBean 是一种特殊的 bean,它是个工厂 bean,可以自己创建 bean 实例,如果一个类实现了 FactoryBean 接口,则该类可以自己定义创建实例对象的方法,只需要实现它的 getObject() 方法即可。

结尾

        面试官,这是我对Spring IOC的整体理解,包含了一些详细的处理过程,您看一下有什么问题,可以指点我一下(心里想看老子不吊打你)

———————————等等面试官还没叫停?—————————————

扩展,还不叫停石锤面试官睡着了,那我们展开继续说(*bean的初始化过程中循环依赖和解决)

刚才说,对象会存储在map结构中,在Spring使用Map结构的singletonObjects存放完整的bean对象。

但是创建这个singletonObjects的过程。Spring在启动的时候会先初始化扫描我们配置的包下面的所有的类,进行解析和注册到beanDecfinition中。然后在根据beanDecfinition的信息对类进行实例化,填充属性等操作变成一个bean,放到我们spring的容器中。在变成bean的过程中,会遇到对象与对象之间的依赖,比如A类中有一个属性B类,那么spring在创建A对象的时候发现了需要一个B对象,这个时候spring就会暂时停止对A的创建,会先去创建B对象,等B对象创建完之后,将B对象注入到A对象中,再接着创建A对象剩下的工作。

这个过程我们分为两部分,首先1、通过反射创建出一个对象,然后2、往对象中的属性赋值。

我们很好理解第一步,我们得到对象的全路径名,就可以利用反射创建A对象,得到A对象中的属性。这时我们会把这个A对象标为正在创建中,并且放到缓存中。

在第二步时就要给属性赋值,这时如果属性中要注入B类的话,spring会首先到容器中找有没有B类的对象,有的话就直接注入在属性上。没有的话就就要重新创建一个B对象,在创建B对象的过程中,必然也会有两步:1、通过反射创建出一个对象,2、往对象中的属性赋值。第一步和之前一样我们不说,第二步的就有可能会注入我们之前正在创建的A对象,同样也到容器中查找,没有找到,因为我们还没有创建完成,这个时候我们会发现他正在创建中,然后我们可以从缓存中取出创建好但没有注入属性值的A对象,然后就去拿着这个A对象给当前B对象注入值。这样就完成了当前B对象的注入。B对象创建完成之后,就会把B对象注入到A中,A对象就创建完成了。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。