当前位置: 首页 > news >正文

【Spring】原理解析:Bean的作用域与生命周期


目录

1.前言

插播一条消息~

2.正文

2.1概念

2.2Bean的作用域

2.2.1singleton(单例)

2.2.2prototype(原型)

2.2.3request(请求)

2.2.4session(会话)

2.2.5application(应用)

2.2.6websocket

2.3Bean的生命周期

2.3.1实例化(Instantiation)

2.3.2属性赋值(Populate)

2.3.3初始化(Initialization)

2.3.4使用(In Use)

2.3.5销毁(Destruction)

2.4源码解析

2.4.1.实例化:createBeanInstance()

2.4.2 属性赋值:populateBean()

2.4.3 初始化:initializeBean()

3.小结


1.前言

在 Spring 容器管理体系中,Bean 的作用域生命周期是两大核心支柱。Bean 的作用域定义了其实例的存活范围与创建策略,例如单例(Singleton)Bean 在容器启动时创建并全局共享,原型(Prototype)Bean 则每次请求时生成新实例,而 Web 环境下的请求(Request)、会话(Session)作用域则与 HTTP 请求周期紧密关联。生命周期则贯穿 Bean 从实例化、属性填充、初始化到销毁的完整过程,通过初始化回调(如 InitializingBean 接口、@PostConstruct 注解)与销毁回调(如 DisposableBean 接口、@PreDestroy 注解)等机制,允许开发者在关键节点植入自定义逻辑,实现资源初始化、缓存预热、连接关闭等精细化控制。

核心价值:深入理解 Bean 的作用域与生命周期,是实现 Spring 应用高性能、高可靠性的基础。错误的作用域配置可能导致线程安全问题(如多线程共享原型 Bean 状态)或资源泄漏(如单例 Bean 持有短生命周期资源),而生命周期管理不当则可能引发初始化失败、资源未释放等运行时异常。因此,掌握这两大机制不仅是 Spring 框架进阶的关键,更是构建健壮企业级应用的前提。

本文将围绕 Spring Bean 的作用域与生命周期展开深度剖析,系统梳理作用域的类型与应用场景、生命周期的关键阶段与扩展点,并结合实际案例揭示其底层实现原理,为开发者提供从理论到实践的完整指导。


插播一条消息~

🔍十年经验淬炼 · 系统化AI学习平台推荐

系统化学习AI平台https://www.captainbed.cn/scy/

  • 📚 完整知识体系:从数学基础 → 工业级项目(人脸识别/自动驾驶/GANs),内容由浅入深
  • 💻 实战为王:每小节配套可运行代码案例(提供完整源码)
  • 🎯 零基础友好:用生活案例讲解算法,无需担心数学/编程基础

🚀 特别适合

  • 想系统补强AI知识的开发者
  • 转型人工智能领域的从业者
  • 需要项目经验的学生

2.正文

2.1概念

在 Spring 框架的设计理念中,IOC(控制反转)容器的核心作用可类比为现代化工厂的生产管理系统。传统软件开发中,对象的创建与依赖管理需开发者手动完成,如同工厂中各车间需自行采购原材料、组装产品,不仅效率低下且耦合度高。而 Spring IOC 容器则扮演着“智能工厂”的角色:它负责统一“生产”(实例化)对象,通过 DI(依赖注入)机制完成“配送”(属性赋值),而 @Autowired 注解则相当于“配送单”,明确指定了目标对象所需的依赖类型,容器据此自动匹配并注入对应的 Bean 实例。这种模式将对象的创建权从业务逻辑层转移至容器,显著降低了组件间的耦合度,使系统更易于维护与扩展。

Bean 作用域的核心定义:如同工厂对产品制定的批次生产规则,Bean 作用域规定了容器中 Bean 实例的创建策略与生命周期边界。它决定了在不同场景下获取 Bean 时,容器返回的是同一个共享实例还是新创建的实例,以及该实例从初始化到销毁的完整存活周期。这一机制是 Spring 实现对象精细化管理的基础,直接影响系统的性能、状态一致性与资源利用率。

通过上述讲解可知,IOC/DI 解决了对象创建与依赖管理的复杂性,而 Bean 作用域则进一步定义了对象的实例化规则。后续章节将详细探讨 Spring 框架提供的 6 种作用域(如 singleton、prototype、request 等),分析其适用场景与实现原理,揭示容器如何根据作用域配置精准控制 Bean 的生命周期。


2.2Bean的作用域

2.2.1singleton(单例)

在 Spring 容器中,singleton 作用域可类比为"工厂只生产一个产品,所有订单都配送同一个实例"的场景:当容器首次启动时,该类型的 Bean 会被创建并初始化,此后所有对该 Bean 的请求都将返回同一个共享实例。这种设计确保了 Bean 在整个应用生命周期内的全局唯一性,是 Spring 容器默认的 Bean 作用域。

代码示例与特性验证

通过以下案例可直观理解 singleton 作用域的实现与特性。首先定义一个简单的 Dog 类作为 Bean 类型:

public class Dog {private String name;// 省略构造方法、getter 和 setter
}

在配置类中使用 @Bean 注解声明 singleton 作用域的 Bean(默认无需显式指定 @Scope("singleton")):

@Configuration
public class AppConfig {@Beanpublic Dog singleDog() {return new Dog("Singleton Dog");}
}

在测试代码中,通过 Spring 容器两次获取 singleDog 实例并比较其哈希码:

public class SingletonTest {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);Dog dog1 = context.getBean("singleDog", Dog.class);Dog dog2 = context.getBean("singleDog", Dog.class);System.out.println("dog1 哈希码:" + dog1.hashCode());System.out.println("dog2 哈希码:" + dog2.hashCode());System.out.println("是否为同一实例:" + (dog1 == dog2));}
}

测试结果显示,两次获取的 Dog 实例哈希码完全相同,且引用比较结果为 true,证明 singleton 作用域下 Bean 实例的全局唯一性。

核心特性总结

  • 创建时机:Spring 容器在启动阶段即完成单例 Bean 的实例化与初始化(非懒加载模式),而非首次请求时创建。
  • 实例管理:容器通过内部缓存机制维护单例实例,所有请求共享同一对象引用。
  • 资源效率:避免重复创建对象,降低内存占用与初始化开销。

2.2.2prototype(原型)

在 Spring 容器的作用域体系中,prototype(原型)作用域可类比为制造业中的“按订单生产”模式——每当客户提交新订单(即程序从容器获取 Bean),工厂都会启动全新的生产流程(实例化过程),产出独一无二的产品(Bean 实例)。这种特性使得 prototype 作用域的 Bean 与 singleton 作用域形成鲜明对比,后者更接近“批量生产的标准化商品”,在容器启动时即完成实例化并全局共享。

从技术实现角度, prototype 作用域的 Bean 通过 @Bean 注解的 scope 属性显式配置。以下代码展示了 prototype 类型 Bean 的典型定义方式:

@Configuration
public class AppConfig {@Bean@Scope("prototype") // 显式指定原型作用域public Dog prototypeDog() {return new Dog();}
}

该配置的核心特性体现为两点:实例化时机的延迟性生命周期管理的自主性。与 singleton Bean 在容器启动阶段完成实例化不同,prototype Bean 仅在调用 getBean() 方法时触发实例化流程;更关键的是,Spring 容器对 prototype 实例的生命周期管理仅负责“创建”环节,而将“销毁”操作完全交由应用程序自行处理,容器不会调用 @PreDestroy 注解的方法或执行其他销毁回调。

为验证 prototype 作用域的实例唯一性,可通过对比多次获取的 Bean 哈希码实现。测试代码如下:

public class PrototypeTest {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);Dog dog1 = context.getBean("prototypeDog", Dog.class);Dog dog2 = context.getBean("prototypeDog", Dog.class);System.out.println("dog1 哈希码:" + dog1.hashCode());System.out.println("dog2 哈希码:" + dog2.hashCode());}
}

执行结果显示两次获取的 Dog 实例哈希码完全不同(例如 dog1: 123456dog2: 789012),直接证明每次获取操作均创建了全新实例。这种特性使其成为有状态组件的理想选择——例如 Web 应用中的请求参数封装类(如 UserForm),每个 HTTP 请求需独立存储用户输入数据,若使用 singleton 作用域将导致请求间状态污染,而 prototype 作用域通过实例隔离从根本上避免了此类问题。

核心结论:prototype 作用域通过“按需创建、实例隔离”的设计,为需要维护独立状态的组件提供了安全解决方案。在实际开发中,应明确区分有状态与无状态组件——对于工具类、服务层对象等无状态组件优先使用 singleton,而请求上下文、会话数据等有状态场景则需采用 prototype 作用域。


2.2.3request(请求)

在 Spring 容器中,request 作用域的 Bean 可类比为快递服务中的产品生产逻辑:同一快递单内的产品保持一致,不同快递单则需重新生产。这意味着 Bean 实例的生命周期与单次 HTTP 请求强绑定,在请求发起时创建,请求完成后销毁,且在同一请求内多次获取的实例完全相同。

配置示例与核心特性

通过 @Scope("request") 注解可定义 request 作用域的 Bean。以下为 requestDog 的配置案例:

@Configuration
public class RequestScopeConfig {@Bean@Scope("request") // 声明为 request 作用域public Dog requestDog() {return new Dog(); // 每次新请求创建新实例}
}

该配置的核心特性体现为:单次 HTTP 请求内唯一实例,请求结束自动销毁。当客户端发起一次 HTTP 请求时,Spring 容器会创建 requestDog 的实例并缓存于请求上下文中,在此请求的处理流程(如 Controller → Service → Repository)中,无论通过 @AutowiredgetBean() 多少次获取该 Bean,得到的都是同一个实例;而当请求响应完成后,该实例会被立即销毁,释放资源

特性验证与测试结果

通过对比同一请求与不同请求中 Bean 的哈希码,可直观验证 request 作用域的唯一性。例如在 Controller 中两次注入 requestDog 并打印其哈希码:

@RestController
public class DogController {@Autowiredprivate Dog requestDog1;@Autowiredprivate Dog requestDog2;@GetMapping("/test-request-scope")public String testRequestScope() {return "同一请求内实例哈希码:" + requestDog1.hashCode() + "," + requestDog2.hashCode();}
}

测试结果显示:同一请求内 requestDog1requestDog2 的哈希码完全相同,证明二者为同一实例;而发起新请求后,哈希码会发生变化,表明新实例已被创建。

关键结论:request 作用域通过绑定 HTTP 请求生命周期,实现了"请求内单例、请求间多例"的特性,有效避免了多线程环境下的实例共享问题。


2.2.4session(会话)

在 Spring 框架的 Bean 作用域体系中,session 作用域体现了“用户会话内实例唯一”的特性,可类比为“同一用户的多次快递配送均使用同一个产品包裹,更换用户则需重新打包新包裹”2:当用户发起多次请求时,Spring 容器会在当前会话周期内复用同一个 Bean 实例;而不同用户会话(如同一个网站的不同登录用户)则会触发新的 Bean 实例创建。这种设计确保了用户会话相关数据的一致性与隔离性。

配置示例与核心特性

要定义 session 作用域的 Bean,需在配置类中通过 @Scope 注解指定作用域类型为 WebApplicationContext.SCOPE_SESSION(或直接使用字符串 "session"),并通常配合 @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) 解决作用域依赖问题。以下是 sessionDog 的配置示例:

session 作用域 Bean 配置代码

@Configuration
public class SessionScopeConfig {@Bean@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)public Dog sessionDog() {return new Dog(); // 每次新会话创建新实例,同会话复用}
}

该配置的核心特点是 “用户会话周期内唯一实例,会话结束销毁”

  • 实例唯一性:同一用户会话(如浏览器未关闭或未超时期间)内,多次获取 sessionDog Bean 会得到相同实例,可通过对象哈希码验证;
  • 生命周期绑定:Bean 实例的创建与销毁完全绑定用户会话生命周期——会话初始化时创建实例,会话失效(如用户退出登录、会话超时或关闭浏览器)时由 Spring 容器自动销毁实例,释放资源。

通过 session 作用域,Spring 框架为 Web 应用提供了高效的会话状态管理机制,平衡了资源复用与数据隔离的需求。


2.2.5application(应用)

在 Spring 框架的 Bean 作用域体系中,application 作用域可类比为"整个工厂的所有生产线共享一个核心产品"——当工厂启动时该产品被制造出来,贯穿整个生产周期,直至工厂关闭才被销毁,且所有生产线(对应 Web 应用中的不同会话、请求)都使用这同一个产品实例。这种作用域特性使其成为 Web 应用级全局资源管理的关键工具。

配置与生命周期特性

通过 @Scope("application") 注解可定义 application 作用域的 Bean,其生命周期严格绑定于 ServletContext:

@Configuration
public class AppConfig {@Bean@Scope("application") // 显式指定 application 作用域public Dog applicationDog() {return new Dog("全局应用共享狗");}
}

该 Bean 会在 Web 应用启动时由 Spring 容器创建,并在 应用停止(ServletContext 销毁)时被回收,期间所有用户会话(Session)、请求(Request)都共享同一个实例。这种生命周期管理使其区别于 singleton 作用域——singleton 是 Spring IoC 容器级别的单例(一个容器一个实例),而 application 是 ServletContext 级别的单例(一个 Web 应用一个实例),即使存在多个 Spring 容器,application 作用域的 Bean 仍保持唯一。

实例共享性验证

通过跨会话获取 Bean 实例并比较哈希码,可直观证明其共享特性。在不同用户会话中执行以下测试代码:

@RestController
public class ScopeTestController {@Autowiredprivate Dog applicationDog;@GetMapping("/test-application-scope")public String testApplicationScope(HttpSession session) {return "会话 ID: " + session.getId() + ", applicationDog 哈希码: " + applicationDog.hashCode();}
}

测试结果显示,无论发起多少个不同会话请求,返回的哈希码始终相同,证实 application 作用域 Bean 在整个应用内的唯一性。


2.2.6websocket

WebSocket 作用域在 Spring 框架中表现为连接周期内的单例实例,其核心特性是为每个独立的 WebSocket 连接创建并维护一个专属的 Bean 实例,该实例的生命周期严格绑定于 TCP 连接的建立与关闭过程。当客户端通过 WebSocket 协议与服务器完成握手并建立持久连接时,Spring 容器会初始化对应的 Bean 实例;而当连接因超时、客户端断开或异常终止时,该实例将被销毁并释放资源。这种设计确保了在长连接存续期间,Bean 能够安全维护连接级别的状态信息,如用户会话上下文、消息序列计数器等,避免多连接共享实例导致的状态混乱问题。

该作用域在实时通信场景中展现出显著优势,典型应用包括即时聊天系统的消息处理器、实时协作工具的状态同步组件、高频数据推送服务(如金融行情更新)等。在这些场景中,WebSocket 连接通常具有数分钟至数小时的生命周期,且需要在连接存续期间保持连续的状态交互,此时作用域的实例隔离机制能够有效提升并发处理效率,降低线程同步开销。

WebSocket 与 Session 作用域关键特性对比

  • 生命周期触发:WebSocket 作用域由 TCP 连接建立/断开触发,Session 作用域由 HTTP 会话创建/超时触发。
  • 实例隔离单位:WebSocket 作用域以物理连接为隔离单位,Session 作用域以逻辑会话为隔离单位。
  • 状态管理目标:WebSocket 作用域聚焦连接存续期间的实时交互状态,Session 作用域侧重用户跨请求的身份与上下文保持。

通过这种精细化的作用域设计,Spring 框架为实时通信场景提供了更贴合底层协议特性的资源管理方案,既满足了长连接状态维护的需求,又通过实例隔离确保了并发安全性,成为构建高性能实时应用的重要技术支撑。


2.3Bean的生命周期

Bean生命周期可类比"产品全生命周期管理":从原材料加工(实例化)→ 零件装配(属性赋值)→ 质检调试(初始化)→ 客户使用(业务调用)→ 回收处理(销毁)。

2.3.1实例化(Instantiation)

核心任务:通过构造函数创建对象毛坯(未设置属性)。

代码示例:

public class BeanLifeComponent {private String name; // 初始nullprivate int age;     // 初始0public BeanLifeComponent() {System.out.println("实例化:name=" + name + ", age=" + age);}
}

输出实例化:name=null, age=0

源码对应AbstractAutowireCapableBeanFactory.createBeanInstance()通过反射调用构造函数。


2.3.2属性赋值(Populate)

核心任务:注入依赖Bean及配置值。

代码示例:

public class UserService {@Autowiredprivate DogComponent dogComponent; // 注入依赖
}

源码对应AbstractAutowireCapableBeanFactory.populateBean()通过类型/名称匹配注入依赖。


2.3.3初始化(Initialization)

执行顺序:Aware接口回调 → @PostConstruct → InitializingBean → init-method

代码示例:

@Component
public class InitDemo implements BeanNameAware {@Overridepublic void setBeanName(String name) {System.out.println("Aware回调:" + name);}@PostConstructpublic void postConstruct() {System.out.println("执行@PostConstruct");}
}

源码对应AbstractAutowireCapableBeanFactory.initializeBean()串联初始化流程。


2.3.4使用(In Use)

Bean处于就绪状态,通过@AutowiredgetBean()获取实例并调用业务方法:

@Autowired
private UserService userService;public void process() {userService.handleData(); // 使用Bean
}

2.3.5销毁(Destruction)

执行顺序:@PreDestroy → DisposableBean → destroy-method

代码示例:

@PreDestroy
public void clean() {System.out.println("释放资源"); // 关闭连接/文件
}

注意:prototype作用域Bean需手动调用销毁方法。

生命周期流程图

Spring Bean 的生命周期是一个从实例化到销毁的完整过程,各阶段按严格顺序衔接,共同确保 Bean 在 IoC 容器中正确初始化、使用和回收。以下通过 PlantUML 流程图直观展示这一过程,并结合文字说明各节点的逻辑关系。

生命周期核心节点顺序:实例化(起点)→ 属性赋值 → 初始化前处理 → 初始化 → 初始化后处理 → 就绪使用 → 销毁前处理 → 销毁(终点)。各阶段通过容器回调机制串联,形成闭环生命周期管理。


2.4源码解析

Spring IoC容器对Bean的生命周期管理可拆解为实例化属性赋值初始化三个核心阶段。通过追踪AbstractAutowireCapableBeanFactory类的核心方法,可清晰理解Spring如何通过反射、自动装配和生命周期回调机制完成Bean的创建过程。

2.4.1.实例化:createBeanInstance()

// 核心逻辑:解析类对象并反射创建实例
Class<?> beanClass = resolveBeanClass(mbd, beanName);
Constructor<?> ctor = beanClass.getDeclaredConstructor();
return ctor.newInstance(); // 反射创建对象

2.4.2 属性赋值:populateBean()

// 核心逻辑:按名称/类型注入依赖
autowireByName(beanName, mbd, bw, pvs); // 按名称匹配
applyPropertyValues(beanName, mbd, bw, pvs); // 设置属性值

2.4.3 初始化:initializeBean()

// 核心逻辑:执行初始化流程
invokeAwareMethods(beanName, bean); // Aware接口回调
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd); // 初始化方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

3.小结

掌握Bean的作用域与生命周期,是理解Spring IoC容器设计思想的基础,也是解决线程安全、资源泄漏等问题的关键。建议结合本文案例代码调试,观察不同作用域下Bean实例的创建与销毁过程,加深理解。

今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,你的支持就是对我最大的鼓励,大家加油!


文章转载自:

http://tsw4NHxU.gjLxn.cn
http://IlWHj6Nd.gjLxn.cn
http://rcQx6xbQ.gjLxn.cn
http://magQ8h8w.gjLxn.cn
http://eaVe6uuU.gjLxn.cn
http://8F83uzyJ.gjLxn.cn
http://caqYIY62.gjLxn.cn
http://oCYDNFvp.gjLxn.cn
http://8TokVPik.gjLxn.cn
http://s18AqEFX.gjLxn.cn
http://3B3lNKGZ.gjLxn.cn
http://6WujIQZ4.gjLxn.cn
http://poprCnah.gjLxn.cn
http://FH9Bs1an.gjLxn.cn
http://mNaNhPmT.gjLxn.cn
http://vdOVmJ7y.gjLxn.cn
http://moQ6iS50.gjLxn.cn
http://OIKujlQc.gjLxn.cn
http://327GRxpd.gjLxn.cn
http://JBzHUiXA.gjLxn.cn
http://mnlJ4wxa.gjLxn.cn
http://zlVHt6HV.gjLxn.cn
http://q4Sa0mcX.gjLxn.cn
http://a3HsDjMq.gjLxn.cn
http://gDf0B77M.gjLxn.cn
http://rpDMlcFH.gjLxn.cn
http://E4HTqZCc.gjLxn.cn
http://RWQYQHID.gjLxn.cn
http://p8QWVplR.gjLxn.cn
http://M2SlO4n6.gjLxn.cn
http://www.dtcms.com/a/373189.html

相关文章:

  • GitLab 分支管理与 Push 问题全解析
  • 基于SpringBoot+MYSQL开发的AI智能大数据医疗诊断平台
  • 分解+优化+预测!CEEMDAN-Kmeans-VMD-DOA-Transformer-LSTM多元时序预测
  • Matlab机器人工具箱使用2 DH建模与加载模型
  • 趣味学RUST基础篇(构建一个命令行程序完结)
  • 基于STM32的智能宠物看护系统设计与实现
  • 基于SpringBoot的家政保洁预约系统【计算机毕业设计选题 计算机毕业设计项目 计算机毕业论文题目推荐】
  • 幂等性、顺序性保障以及消息积压
  • 第一次使用coze工作流,生成简易行业报告
  • tl;dv:让你的会议更高效
  • 【入门级-算法-6、排序算法: 插入排序】
  • 健康度——设备健康续航条
  • 深入理解Spring Boot的EnvironmentPostProcessor:环境处理的黑科技
  • 面向生产环境的大模型应用开发
  • elastic search 是如何做sum操作的
  • HashMap高频面试题目
  • 李沐深度学习论文精读(二)Transformer + GAN
  • 达梦数据库(DM8)单机数据库安装部署
  • 《sklearn机器学习——特征提取》
  • OnlyOffice的高可用方案如何做
  • 苍穹外卖前端Day1 | vue基础、Axios、路由vue-router、状态管理vuex、TypeScript
  • 【RabbitMQ】----RabbitMQ 的7种工作模式
  • CN2 GIA线路深度解析:阿里云/腾讯云选哪个?(附三网评测)
  • 冰火岛 Tech 传:Apple Foundation Models 心法解密(下集)
  • Gamma AI:高效制作PPT的智能生成工具
  • 云计算学习笔记——HTTP服务、NFS服务篇
  • unity入门:按钮控制横向滚动视窗显示最左最右
  • 大模型为什么会有幻觉?-Why Language Models Hallucinate
  • 数据结构造神计划第三天---数据类型
  • MYSQL集群高可用架构之MHA高可用架构