栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Bean

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Bean

文章目录
  • 什么是bean对象?
  • bean的作用域
    • 有状态的bean与无状态的bean
    • singleton vs prototype
  • Bean的循环依赖
    • 什么是循环依赖?
    • 三级缓存解决循环依赖
    • 二级缓存可以么?
  • Bean生命周期

什么是bean对象?

由spring容器管理的对象统称为Bean对象。
Bean就是普通的java对象,和我们自己new的对象其实是一样的,只是这些对象是由spring去创建和管理的

bean的作用域 有状态的bean与无状态的bean

有状态bean:
每个用户有自己特有的一个实例,在用户的生存期内,bean保存了用户的信息——即有状态;
一旦用户灭亡,bean的生命期也告结束。

无状态bean:
bean一旦实例化就被加进会话池中,各个用户都可以共用。即使用户已经消亡,bean的生命期也不一定结束,它可能依然存在于会话池中,供其他用户调用。
由于没有特定的用户,那么也就不能保持某一用户的状态——即无状态bean。

二者线程安全性
有状态就是有数据存储功能,可以保存数据——非线程安全
无状态就是一次操作不能保存数据。不能保存数据是不变类——线程安全

singleton vs prototype

spring为什么要设置多种作用域?
应用中,有时候我们需要一个对象在整个应用中只有一个,而有些时候又希望对象每次使用的时候都重新创建一个,spring为了满足这些不同的需求,设置了不同的作用域方便我们使用

singleton vs prototype:

  • singleton单例——无状态bean
    默认的作用域, Spring容器只存在一个共享的bean实例,每个用户获取得到的是同一个bean;

  • prototype多例——有状态bean
    每个用户从容器中获取bean都会为其创建一个独有的bean,可以保存其状态。

Bean的循环依赖 什么是循环依赖?

多个bean之间相互依赖,形成了一个闭环。

比如:A依赖于B、B依赖于C、C依赖于A。

代码中表示:

public class A{
    B b;
}
public class B{
    C c;
}
public class C{
    A a;
}
三级缓存解决循环依赖

先看下三级缓存分别存放什么:

  • singletonObjects:一级缓存,用于存放完整的 bean,从该缓存中取出的 bean 可以直接使用;
  • earlySingletonObjects:二级缓存,存放提前暴露的 bean,bean 是只完成了实例化,未完成属性注入和初始化,用于解决循环依赖;
  • singletonFactories:三级缓存,存放的是 Bean 工厂,主要用于生产 Bean,然后存放到二级缓存中。

Spring利用三级缓存解决循环依赖的过程:

1、实例化 A,此时 A 还未完成属性填充和初始化方法的执行,A 只是一个半成品。
2、为 A 创建一个 Bean 工厂,并放入到 三级缓存中。
3、发现 A 需要注入 B 对象,但是一级、二级、三级缓存均未发现对象 B。
4、实例化 B,此时 B 还未完成属性填充和初始化方法的执行,B 只是一个半成品。
5、为 B 创建一个 Bean 工厂,并放入到三级缓存中。
6、发现 B 需要注入 A 对象,此时在一级、二级未发现对象 A,但是在三级缓存中发现了对象 A,从三级缓存中得到对象 A,并将对象 A 放入二级缓存中,同时删除三级缓存中的对象 A。(注意,此时的 A 还是一个半成品,并没有完成属性填充和执行初始化方法)
7、将对象 A 注入到对象 B 中。
8、对象 B 完成属性填充,执行初始化方法,并放入到一级缓存中,同时删除二级缓存中的对象 B。(此时对象 B 已经是一个成品)
9、对象 A 得到对象 B,将对象 B 注入到对象 A 中。(对象 A 得到的是一个完整的对象 B)
10、对象 A 完成属性填充,执行初始化方法,并放入到一级缓存中,同时删除二级缓存中的对象 A。

Spring 在注入属性的时候是如何去获取依赖的呢?
当 Spring 为某个 Bean 填充属性的时候,它首先会寻找需要注入对象的名称,然后依次执行 getSingleton() 方法得到所需注入的对象,而获取对象的过程就是先从一级缓存中获取,一级缓存中没有就从二级缓存中获取,二级缓存中没有就从三级缓存中获取,如果三级缓存中也没有,那么就会去执行 doCreateBean() 方法创建这个 Bean。
getSingleton()方法源码如下:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 一级缓存
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 二级缓存
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // 三级缓存
                ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    // Bean 工厂中获取 Bean
                    singletonObject = singletonFactory.getObject();
                    // 放入到二级缓存中
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}
二级缓存可以么?

如果注入的是普通对象的话可以,但如果是代理对象的话不行。
因为如果 Spring 选择二级缓存来解决循环依赖的话,那么就意味着所有 Bean 都需要在实例化完成之后就立马为其创建代理,但是Spring 的设计原则是在 Bean 初始化完成之后才为其创建代理。二级缓存不满足,所以Spring 选择了三级缓存。

为什么代理对象时就需要在实例化之后立马为其创建代理?
这就和AOP有关,如果创建的 Bean 是有代理的,那么注入的就应该是代理 Bean,而不是原始的 Bean。
但是 Spring 一开始并不知道 Bean 是否会有循环依赖,在没有循环依赖的情况下,Spring 都会在完成填充属性,并且执行完初始化方法之后再为其创建代理。但是,如果出现了循环依赖的话,Spring 就不得不为其提前创建代理对象,否则注入的就是一个原始对象,而不是代理对象。因此,这里就涉及到应该在哪里提前创建代理对象?Spring 的做法就是在三级缓存中去提前创建代理对象。
文章目录
什么是循环依赖?
三级缓存解决循环依赖
二级缓存可以么?
什么是循环依赖?
多个bean之间相互依赖,形成了一个闭环。

比如:A依赖于B、B依赖于C、C依赖于A。

代码中表示:

public class A{
B b;
}
public class B{
C c;
}
public class C{
A a;
}
三级缓存解决循环依赖
先看下三级缓存分别存放什么:

singletonObjects:一级缓存,用于存放完整的 bean,从该缓存中取出的 bean 可以直接使用;
earlySingletonObjects:二级缓存,存放提前暴露的 bean,bean 是只完成了实例化,未完成属性注入和初始化,用于解决循环依赖;
singletonFactories:三级缓存,存放的是 Bean 工厂,主要用于生产 Bean,然后存放到二级缓存中。
Spring利用三级缓存解决循环依赖的过程:

1、实例化 A,此时 A 还未完成属性填充和初始化方法的执行,A 只是一个半成品。
2、为 A 创建一个 Bean 工厂,并放入到 三级缓存中。
3、发现 A 需要注入 B 对象,但是一级、二级、三级缓存均未发现对象 B。
4、实例化 B,此时 B 还未完成属性填充和初始化方法的执行,B 只是一个半成品。
5、为 B 创建一个 Bean 工厂,并放入到三级缓存中。
6、发现 B 需要注入 A 对象,此时在一级、二级未发现对象 A,但是在三级缓存中发现了对象 A,从三级缓存中得到对象 A,并将对象 A 放入二级缓存中,同时删除三级缓存中的对象 A。(注意,此时的 A 还是一个半成品,并没有完成属性填充和执行初始化方法)
7、将对象 A 注入到对象 B 中。
8、对象 B 完成属性填充,执行初始化方法,并放入到一级缓存中,同时删除二级缓存中的对象 B。(此时对象 B 已经是一个成品)
9、对象 A 得到对象 B,将对象 B 注入到对象 A 中。(对象 A 得到的是一个完整的对象 B)
10、对象 A 完成属性填充,执行初始化方法,并放入到一级缓存中,同时删除二级缓存中的对象 A。

Spring 在注入属性的时候是如何去获取依赖的呢?
当 Spring 为某个 Bean 填充属性的时候,它首先会寻找需要注入对象的名称,然后依次执行 getSingleton() 方法得到所需注入的对象,而获取对象的过程就是先从一级缓存中获取,一级缓存中没有就从二级缓存中获取,二级缓存中没有就从三级缓存中获取,如果三级缓存中也没有,那么就会去执行 doCreateBean() 方法创建这个 Bean。
getSingleton()方法源码如下:

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 一级缓存
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 二级缓存
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 三级缓存
ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// Bean 工厂中获取 Bean
singletonObject = singletonFactory.getObject();
// 放入到二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
二级缓存可以么?
如果注入的是普通对象的话可以,但如果是代理对象的话不行。
因为如果 Spring 选择二级缓存来解决循环依赖的话,那么就意味着所有 Bean 都需要在实例化完成之后就立马为其创建代理,但是Spring 的设计原则是在 Bean 初始化完成之后才为其创建代理。二级缓存不满足,所以Spring 选择了三级缓存。

为什么代理对象时就需要在实例化之后立马为其创建代理?
这就和AOP有关,如果创建的 Bean 是有代理的,那么注入的就应该是代理 Bean,而不是原始的 Bean。
但是 Spring 一开始并不知道 Bean 是否会有循环依赖,在没有循环依赖的情况下,Spring 都会在完成填充属性,并且执行完初始化方法之后再为其创建代理。但是,如果出现了循环依赖的话,Spring 就不得不为其提前创建代理对象,否则注入的就是一个原始对象,而不是代理对象。因此,这里就涉及到应该在哪里提前创建代理对象?Spring 的做法就是在三级缓存中去提前创建代理对象。

Markdown 2090 字数 77 行数 当前行 74, 当前列 26 文章已保存20:05:44 HTML 2071 字数 61 段落

Bean生命周期

核心的包括下面9个阶段:
阶段1:Bean元信息配置阶段

阶段2:Bean元信息解析阶段

阶段3:将Bean注册到容器中

阶段4:Bean Class加载阶段

阶段5:Bean实例化阶段

阶段6:属性赋值阶段

阶段7:Bean初始化阶段

阶段8:Bean的使用阶段

阶段9:Bean销毁阶段

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1003704.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号