Spring Bean----5.27学习小记

一、Bean 的作用域

1. 什么是 Bean 作用域?

Bean 作用域是 Spring 用来控制 Bean 实例数量与存活范围的机制,简单说就是:每次从容器中获取 Bean 时,是复用同一个对象,还是新建一个对象。

Spring 内置了 6 种作用域,其中 4 种是通用作用域,另外 2 种是 Web 专属作用域。

2. 六大作用域详解

表格

作用域类型 含义 实例数量 适用场景
singleton 单例作用域,整个 Spring 容器仅一个实例 1 个 工具类、Service、Dao、Controller(无状态 Bean)
prototype 原型多例作用域,每次获取都新建实例 多个 有状态 Bean、需要独立对象的场景
request 一次 HTTP 请求对应一个 Bean 实例 请求级 Web 项目,请求临时数据存储
session 一个用户会话对应一个 Bean 实例 会话级 存储用户登录信息、会话数据
application 整个 Web 应用全局唯一,与容器同生命周期 全局 全局配置信息
websocket 一次 WebSocket 连接对应一个 Bean 实例 连接级 即时通讯、WebSocket 长连接场景

3. 重点作用域代码实战

(1)singleton 单例(默认)

Spring 容器启动时就直接创建实例,全局共享,所有获取操作拿到的都是同一个对象。

复制代码
<bean id="dog" class="com.qcby.Dog" scope="singleton"/>
  • 注解方式:

    @Component
    @Scope("singleton") // 可省略,默认就是单例
    public class Dog {}

✅ 特点:容器启动初始化一次、全局唯一、性能高,但非线程安全(多线程修改共享状态会有问题)。

(2)prototype 多例

容器启动时不创建 Bean,每次getBean或注入时才新建对象。

复制代码
@Component
@Scope("prototype")
public class Dog {}

✅ 特点:多实例、线程安全,但 Spring 不管理多例 Bean 的销毁生命周期,需要自己手动处理资源释放。


二、Bean 的完整生命周期:从诞生到销毁的全过程

Bean 的生命周期,就是 Bean 在 Spring IoC 容器中,从创建到销毁的完整流程,也是面试的高频考点。

1. 完整生命周期流程图

容器启动 → 实例化 → 属性赋值 → 预处理 → 初始化 → 后置处理 → 就绪使用 → 容器关闭销毁

2. 七步详细拆解

第一步:实例化(new 对象)

Spring 启动时,通过反射调用无参构造方法,创建 Bean 的空对象。 ⚠️ 关键提醒:必须有无参构造,否则 Bean 会创建失败(这也是很多启动报错的核心原因)。

第二步:属性赋值(依赖注入)

通过setter方法、构造函数、@Autowired等方式,给 Bean 的成员变量赋值,完成依赖注入。 ⚠️ 对应报错:没有setter方法、属性不可写 → 注入失败。

第三步:执行 Aware 接口(容器回调)

Spring 内置的扩展接口,让 Bean 感知容器资源:

  • BeanNameAware:获取当前 Bean 的名称
  • BeanFactoryAware:获取 Bean 工厂对象
  • ApplicationContextAware:获取 Spring 容器上下文
第四步:Bean 前后置处理器(BeanPostProcessor)

Spring 提供的全局增强机制,在 Bean 初始化前后执行自定义逻辑,是 Spring AOP、注解增强的核心原理。

  • 前置处理:postProcessBeforeInitialization
  • 后置处理:postProcessAfterInitialization
第五步:初始化(自定义初始化逻辑)

有 3 种初始化执行方式,优先级从高到低:

  1. @PostConstruct注解(推荐,最常用)
  2. 实现InitializingBean接口
  3. XML 配置init-method属性
第六步:Bean 就绪(使用阶段)

初始化完成后,Bean 正式存入 Spring 单例池,对外提供服务,接收程序调用。

第七步:销毁(容器关闭)

Spring 容器关闭时,执行 Bean 的销毁逻辑,仅针对单例 Bean 生效。两种销毁方式:

  • @PreDestroy注解
  • 实现DisposableBean接口

3. 生命周期完整代码演示

复制代码
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.DisposableBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class LifeCycleBean implements BeanNameAware, InitializingBean, DisposableBean {

    private String beanName;

    // 1. 实例化(无参构造)
    public LifeCycleBean() {
        System.out.println("第一步:调用无参构造,实例化Bean");
    }

    // 2. 属性赋值(模拟依赖注入)
    public void setBeanName(String name) {
        System.out.println("第二步:属性赋值,设置beanName");
        this.beanName = name;
    }

    // 3. Aware接口回调
    @Override
    public void setBeanName(String name) {
        System.out.println("第三步:执行BeanNameAware,获取Bean名称:" + name);
        this.beanName = name;
    }

    // 4. 初始化方式1:@PostConstruct
    @PostConstruct
    public void postConstruct() {
        System.out.println("第五步:执行@PostConstruct初始化方法");
    }

    // 4. 初始化方式2:InitializingBean接口
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("第五步:执行InitializingBean的afterPropertiesSet方法");
    }

    // 销毁方式1:@PreDestroy
    @PreDestroy
    public void preDestroy() {
        System.out.println("第七步:执行@PreDestroy销毁方法");
    }

    // 销毁方式2:DisposableBean接口
    @Override
    public void destroy() throws Exception {
        System.out.println("第七步:执行DisposableBean的destroy方法");
    }
}

4. 生命周期执行顺序总结

无参构造实例化 → 属性赋值 → Aware 接口 → 前置处理器 → @PostConstruct → InitializingBean → init-method → 后置处理器 → Bean 使用 → 容器关闭销毁


三、作用域与生命周期的关联关系

  1. singleton 单例 :容器启动完成实例化、属性赋值、初始化,容器关闭销毁,完整生命周期由 Spring 管理。
  2. prototype 多例 :调用时才创建,Spring 只负责创建和属性赋值,不管理初始化和销毁,需要开发者自己处理资源释放。
  3. Web 作用域(request/session):生命周期随请求 / 会话结束而终止,Spring 会在请求 / 会话结束时自动销毁 Bean。

四、结语

Bean 的作用域和生命周期,是 Spring IoC 最核心、最基础的知识点,也是面试和开发的必考点。

  • 掌握作用域,能帮你合理设计 Bean 的实例模型,避免线程安全问题;
  • 掌握生命周期,能帮你解决依赖注入失败、资源泄漏、初始化逻辑异常等 90% 的常见问题。
相关推荐
桃西西呀3 分钟前
Spring AI Alibaba 之七:我没写一行 tracing 埋点,Agent 每一步却被 Micrometer 看得清清楚楚
人工智能·spring·llm
桃西西呀3 分钟前
Spring AI Alibaba 之八:我让 Agent 直接执行 shell 命令,它却读到了目录里的密钥,沙箱到底防住了什么
人工智能·spring·llm
荣码4 分钟前
从0到1搭一个生产级RAG系统:串联前面21篇所有知识
java·python
xuxigifxfh6 分钟前
牛客:HJ170 01序列
java·开发语言·算法·华为机考
m4Rk_18 分钟前
【论文阅读】Agent 记忆机制(96):M3-Agent——让 Agent 从视听经历中持续形成情景与语义长期记忆
论文阅读·人工智能·学习·开源·github
野生技术架构师28 分钟前
牛客网互联网大厂 Java 高频面试题整理(持续更新)
java·开发语言
小师兄吃牛肉1 小时前
Java语法 | 多重循环
java·开发语言·python
Han.miracle1 小时前
MySQL InnoDB:MVCC、记录锁、间隙锁、二级索引MVCC底层原理
java·开发语言
不停喝水1 小时前
【前端转全栈java速通课】 项目实战④7-11节 操作数据库-登录-注册-修改密码-注销-mubatis-plus简化crud-
java·前端·数据库
y1su2 小时前
Leetcode 二分模板
java·数据结构·算法·leetcode·排序算法