Spring——IOC与容器的创建过程到底是怎么回事

什么是IOC和容器

原本在代码中对象由开发者自己管理,自己去创建。那么把对象交给Sprin去管理,从对象的创建到销毁,都由spring来控制,用户只需要使用的思想,就成为IOC依赖反转。那么spring既然要管理这么多的bean对象,就需要有一个去装载这些对象的地方或者说是东西,在程序运行过程中,从这里面里去拿,那么装载这些bean对象的就叫是容器。

在这里插入图片描述

Spring如何解析读取bean对象

要想让Spring管理bean对象,就需要让Spring知道有哪些bean对象需要被管理。常用的方式有很多种,比如xml文件中通过标签的配置方式,properties配置文件,yaml配置文件,注解的等等不通的方式。并且每个类的类名,属性,方法等等信息都是不一样的。那么这里就有两个问题。

  • bean的定义方式有很多种,那么解析他的方式对应的也会有很多个不同类,去分别实现不同的解析逻辑。那么在这些类的上面,就会有一个接口,里面定义了解析bean的方法,然后他的子类分别去实现不通格式bean的解析。这个接口就是BeanDefinitionReader
  • 在面对不同的bean时,都要交给Spring管理,那么肯定需要解析到一个统一的类对象中去,这个类在Spring源码中就叫做BeanDefinition,它里面负责存放每个被解析的bean对象的名称,属性等等信息。
  • 在这里插入图片描述

BeanDefinition放在哪里

都说BeanDefinition放在容器里,这个说法摸棱两可。在非web环境下,我们通常会用ApplicationContext.getBean(“xxx”)去从容器中获取bean对象,这个ApplicationContext叫做上下文对象,虽然他能访问容器了,但他还不是最顶层的东西,在他的上面还有一个BeanFactory,在源码中给的定义是“The root interface for accessing a Spring container”,也就是访问容器的根入口,那么我们操作BeanFactory也就是操作容器,所以在某种意义上说,BeanFactory也就等同于是容器。那么我们通过BeanDefinitionReader解析后得到的BeanDefinition对象都会放在BeanFactory中。
在这里插入图片描述

BeanFactoryPostProcessor是干嘛的

有了BeanDefiniction对象之后,里面虽然存放好了被解析的类中的详细信息,但是有了BeanDefiniction对象之后就直接new出来实例化了,这也太简单了,并且这也失去了Spring框架的意义,并且也不适用于很多业务场景。所以,创建bean对象的过程远远不止这样…

在以前用xml文件加载数据源bean的时候,里面的value值往往又是从另一个文件中去读取的,在xml文件中是以${xxxx}的形式表示,那么在BeanDefinitionReader读取装载到BeanDefinition中后,并不会进行值的替换,这个bean中的各个属性的值存放的就是"${xxxx}"的一个字符串,这显然不能达到实例化bean的要求。

<bean id = "dataSource" class="com.alibaba.druid.pool.DruidDataSource">
	<property name="url" value="${jdbc.url}"></property>
	<property name="uername" value="${jdbc.username}"></property>
	...
</bean>

所以在这里Spring就有个东西叫做PostProcessor后置处理器的东西。在源码中它有两个分支,一个是BeanPostProcessor 针对Bean对象进行处理,另一个是BeanFactoryPostProcessor 针对BeanFactory进行处理。那么现在BeanDefinition还没有被实例化成Bean,并且放在BeanFactory中,所以这里Spring又会用一个或多个BeanFactoryPostProcessor的实现类做一系列的事情了。比如用PlaceHolderConfigurerSupport实现类去处理${}占位符的值替换。
在这里插入图片描述

实例化与初始化的区别

现在BeanDefiniction已经经过了一系列BeanFactoryPostProcessor处理,里面真真实实的记录了一个类的名称,属性,属性值,构造器等等信息。那么现在具备了条件,Spring就直接能把这个bean对象创建出来使用了吗?当然没有那么简单。
对象的创建分为实例化和初始化,实例化只是在堆空间中开辟一块空间给该对象,但此时对象中的属性都是默认值。
实例化后,才开始初始化对象,在初始化中才给对象的属性填充值,并且调用对象的初始化方法等等扩展的功能,完善该对象。
在这里插入图片描述
所以,在前面的BeanDefinition经过一系列的BeanFactoryPostProcessor处理之后,紧接着下一步先是通过反射进行实例化。
在这里插入图片描述

Spring初始化bean的具体过程

前面提到过,有个东西叫PostProcessor后置处理器的东西。它有两个分支,一个是BeanPostProcessor针对Bean对象进行处理,另一个是BeanFactoryPostProcessor针对BeanFactory进行处理。
那么在这里,初始化的过程中,需要对Bean对象做的一系列事情,肯定就需要BeanFactory来处理了。
在源码中接口上的注释里它已经给我们列举了大致的步骤,如下:

  • 填充属性,也就是调用set方法
  • 调用aware接口方法
  • 执行postProcessBeforeInitialization方法(简称before方法)
  • 调用init方法
  • 执行postProcessAfterInitialization方法(简称after方法)
  • 得到完整的bean对象,可以直接使用
  • 销毁
    上面主要看BeanPostProcessor接口中的before和after方法。只要在Spring中涉及了PostProcessor的都是可用于扩展操作的。例如AOP动态代理,就是有个AbstractAutoProxyCreatpr类实现了这个接口,在源码里可以看到,它的before方法仅是直接返回对象,没做啥处理,但在after方法中做了一些列操作,先判断bean对象是否为空,如果不为空再判断他是否被代理了等等操作,最后获取这个对象的代理。
    在这里插入图片描述

总结

Spring中一个对象从解析到加载,再经过层层处理最终变成一个容器中的对象供Spring调用的过程,大致可以总结为以下几步:

  • 1.创建容器
  • 2.用BeanDefinition读取解析xml配置文件中或yaml各种途径定义的bean信息,封装成BeanDefinition放入容器中
  • 3.调用执行BeanFactoryPostProcessor各个实现子类处理- 项目
    • 调用BeanFactoryPostProcessor各个实现子类是不是单纯的链式,而是循环执行的
  • 4.实例化
  • 5.初始化
    • 初始化中的填充属性,调用aware,before,init,after各个步骤也不是链式执行的,同样是是循环执行的
  • 6.得到完整对象
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java大魔王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值