Spring Bean 的生命周期


一、前言

本文将图文并茂的为你讲述spring 中 bean 的生老病死!!!


二 、Bean 的生命周期

生命周期: 从对象的创建到使用到销毁的过程

在这里插入图片描述

2.1 Bean 的定义信息

BeanFactory: Bean 工厂,是 Spring 的一个根接口

PostProcessor:后置处理器

  • BeanFactoryPostProcessor: 处理 Bean 的定义信息 BeanDifinition

  • BeanPostProcessor:修改 Bean 的信息

请添加图片描述

请添加图片描述

2.2 Bean 的创建

Aware 接口:

当容器中创建的 Bean 对象需要进行具体操作时,需要容器的其他对象,可以实现 Aware 接口,来进行操作,用于二次开发。

在这里插入图片描述

2.3 Bean 的使用

在 Bean 创建时,属性赋值完成后,理论上 Bean 对象已经可以拿来使用了,但是Spring 考虑扩展性,会对 Bean 再做一些处理,完成初始化后即可调用

2.4 Bean 的销毁

Bean的销毁是在 Spring 容器关闭时进行销毁,及context.close()方法。

2.5 循环依赖

Spring 中的 Bean 默认情况下是单例的

2.5.1 什么是循环依赖

A 对象内包含了属性 b,B 对象内包含了属性 a。对 A 对象进行实例化后,对 b 属性赋值,这时候会引用 B 对象,判断 容器中是否有 B 对象,有则赋值,无则创建,B同理,这样程序就会报循环依赖的错误。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-z7FZO4LG-1675153914716)(img/循环依赖.svg)]

2.5.2 Spring 解决循环依赖

解决方案:三级缓存、提前暴漏对象

当持有了某一个对象的引用之后,能否在后续步骤中给对象进行赋值操作?

可以,这样就可以解决循环依赖,其解决循环依赖的本质是 Bean 的实例化和初始化可以分开执行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gOPcWWyL-1675153914716)(img/Spring 循环依赖.svg)]

2.5.2.1 三级缓存

DefaultSingletonBeanRegistry 源码

	/**
	* 一级缓存
	* Cache of singleton objects: bean name to bean instance. */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/**
	* 三级缓存
	* 用于保存 BeanName 和 创建 Bean 的工厂之间的联系
	* Cache of singleton factories: bean name to ObjectFactory. */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/**
    * 二级缓存
    * 保存 BeanName 和 创建 Bean 实例之间的联系,与 singletonFactories 的不同在于,当单例 Bean 被放到这里后,就可以通过 getBean 方法获取到,可以方便进行循环依赖的检测
    * Cache of early singleton objects: bean name to bean instance. */
	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

一级缓存二级缓存三级缓存
实例化对象类型ConcurrentHashMapConcurrentHashMapHashMap
容量2561616
泛型ObjectObjectObjectFactory

ObjectFactory:不是对象工厂,是函数式接口

@FunctionalInterface
public interface ObjectFactory<T> {

/**
    * Return an instance (possibly shared or independent)
    * of the object managed by this factory.
    * @return the resulting instance
    * @throws BeansException in case of creation errors
    */
   T getObject() throws BeansException;

}

jdk1.8后可以将 lambda 表达式作为参数放到方法的参数中,在方法执行的时候,并不会实际调用当前 lambda 表达式,只有在调用 getObject 方法的时候再回去调用 lambda 表达式

2.5.2.2 提前暴露

提前暴露指的是在 Bean 创建完成前 将对象暴露出去,Spring 在解决循环依赖问题时,在实例化后就将未创建完成的 Bean 的 ObjectFactory 放到 三级缓存,这样就把 Bean 提前暴露出去。

2.5.3 注意
2.5.3.1 三级缓存结构中 map 分别存储什么类型对象

一级缓存:成品对象

二级缓存:半成品对象

三级缓存:lambda 表达式

2.5.3.2 三级缓存结构进行对象查找时,顺序是什么?

一级缓存 ==> 二级缓存 ==> 三级缓存

2.5.3.3 如果只有一个 map 结构可以解决循环依赖问题吗?

理论上可行,实际没人这么干

使用两个 map 的意义在于 将成品对象和半成品对象进行区分,半成品对象不能暴露给外部使用,可以设置 标识位进行区分,但是操作比较麻烦,所以直接使用两个 map

2.5.3.4 如果只有两个 map 结构 可以解决循环依赖吗?

可以解决,但是前提是 没有使用代理对象的时候,当不使用 AOP 的时候, 两个 map 就可以解决循环依赖问题

2.5.3.5 为什么使用三级缓存可以解决带 AOP 的循环依赖问题
  • 一个容器中不能包含同名对象

  • 对象创建过程中,扩展阶段 原始对象有可能需要生成代理对象

  • 当代理对象出现时,要使用代理对象替换掉原始对象

  • 代理对象的创建是在初始化过程的扩展阶段,需要在前置处理过程的时候判断是否需要生成代理对象

  • 为什么使用 lambda 表达式(函数式接口)

    因为对象什么时候被暴露或被引用无法提前预知,所以只有在被调用的时候才可进行原始对象还是代理对象的判断,使用 lambda 表达式延迟执行的优点,类似于一种回调机制,不暴露的时候不执行,当需要被调用的时候才真正执行 lambda 表达式,来判断返回的是代理对象还是原始对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值