Bean 是什么 | Bean 的作用域 | Bean 的生命周期 | Spring 循环依赖问题及解决方案

Bean 是什么?

在 Spring 中,Bean 是指被 Spring IoC(控制反转)容器管理的对象。通常情况下,Bean 是指应用程序中的对象,它们是由 Spring 容器在启动时自动创建并管理的。

Spring 的核心思想就是 IoC(控制反转),即将对象的创建和管理交给容器,而不是由程序员手动去创建和管理这些对象。在 Spring 中,容器会根据配置的类(可以是 Java 配置、XML 配置等)来实例化、配置和管理这些对象(Bean)。

是否是所有对象都是 Bean?

并不是所有对象都可以是 Spring 的 Bean。只有那些被 Spring IoC 容器管理的对象才是 Bean。通常,这些 Bean 是由 Spring 容器根据配置类、XML 配置文件等自动创建的对象,而不是我们手动创建的普通对象。

Bean 的作用域

Spring 提供了多种作用域来控制 Bean 的生命周期和可见范围。以下是常见的几种作用域:

  1. 单例(Singleton)

    • 这是 Spring 中的默认作用域。
    • Spring IoC 容器只会创建一个 Bean 实例,并且所有请求该 Bean 的地方都会返回相同的实例。
    • 适用于大多数场景,比如数据库连接池等。
  2. 原型(Prototype)

    • 每次请求该 Bean 时,Spring 都会创建一个新的 Bean 实例。
    • 适用于每次请求需要不同状态的场景,比如临时的对象。
  3. 请求(Request)

    • 这种作用域仅在 web 应用中有效。
    • 每次 HTTP 请求都会创建一个新的 Bean 实例。
    • 适用于在一次请求周期内需要一个特定 Bean 实例的场景。
  4. 会话(Session)

    • 这种作用域也仅在 web 应用中有效。
    • 每个 HTTP 会话都有一个独立的 Bean 实例。
    • 适用于需要在整个会话周期内维持状态的场景。
  5. 应用(Application)

    • 这种作用域也仅在 web 应用中有效。
    • 所有的 Bean 在整个 Web 应用中共享同一个实例。
  6. WebSocket

    • 每个 WebSocket 会话都有一个独立的 Bean 实例。
    • 适用于 WebSocket 应用中,需要在 WebSocket 生命周期内维持状态的场景。

Bean 的生命周期

Spring Bean 的生命周期是指 Bean 从创建到销毁的整个过程。主要步骤如下:

  1. 实例化 Bean

    • Spring 容器通过构造器或工厂方法创建 Bean 实例。
  2. 设置 Bean 的属性

    • Spring 会将配置的属性注入到 Bean 中(依赖注入),这些属性可能是其他 Bean 的引用。
  3. 检查 Aware 接口并设置相关依赖

    • 如果 Bean 实现了 BeanNameAwareBeanFactoryAware 接口,容器会调用相应的方法来注入相关信息(如 Bean 的名称,容器的引用等)。
  4. BeanPostProcessor 的处理

    • BeanPostProcessor 是一个用于修改 Bean 的回调接口。在属性注入之后,Spring 会调用所有注册的 BeanPostProcessorpostProcessBeforeInitialization 方法。
  5. 初始化 Bean

    • 如果 Bean 实现了 InitializingBean 接口,Spring 会调用 afterPropertiesSet 方法。
    • 如果 Bean 定义了 init-method,Spring 也会调用这个方法。
  6. BeanPostProcessor 第二次调用

    • 在初始化之后,Spring 会再次调用所有注册的 BeanPostProcessorpostProcessAfterInitialization 方法。
  7. 使用 Bean

    • 这时 Bean 已经准备好,可以被应用程序使用。
  8. 销毁 Bean

    • 当容器关闭时,如果 Bean 实现了 DisposableBean 接口,Spring 会调用其 destroy 方法。
    • 如果 Bean 定义了 destroy-method,Spring 也会调用这个方法。

Spring 循环依赖问题及解决方案

循环依赖是什么?

循环依赖是指两个或多个 Bean 相互依赖,形成了一个闭环。例如,Bean A 依赖 Bean B,而 Bean B 又依赖 Bean A,这就构成了一个循环依赖。

如何检测循环依赖?

Spring 会在创建 Bean 时为每个 Bean 打标。如果在创建过程中,某个 Bean 还没有完全初始化并且再次请求该 Bean,容器就会检测到循环依赖。

如何解决循环依赖?
  1. 构造器注入不支持循环依赖

    • 由于 Spring 需要完全实例化 Bean 才能注入构造函数的依赖,因此构造器注入不能解决循环依赖。
  2. 字段注入或 Setter 注入解决循环依赖

    • Spring 使用三级缓存来解决循环依赖问题:
      • 一级缓存:存放 Bean 的原始实例。
      • 二级缓存:存放已经创建并且属性已设置的 Bean。
      • 三级缓存:存放尚未设置属性的 Bean。

    当 Spring 创建 Bean 时,首先创建一个原始实例,将其放入一级缓存。当 Bean 的属性需要注入其他 Bean 时,Spring 会检查二级缓存,若该 Bean 还未准备好,则创建并放入三级缓存。属性注入完成后,Bean 会放入二级缓存。

  3. 使用 @Lazy 注解

    • 使用 @Lazy 注解可以延迟 Bean 的加载,只有在真正需要时才会创建 Bean,这也能避免一些循环依赖问题。

通过这些机制,Spring 能够解决大部分常见的循环依赖问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值