目录
[2.3.4使用(In Use)](#2.3.4使用(In Use) "#toc-07f16dfb0b9ed170a024a0e15f53e7b0")
2.4.1.实例化:createBeanInstance()
[2.4.2 属性赋值:populateBean()](#2.4.2 属性赋值:populateBean() "#toc-83a1a1afc8b746e1a7198eaa479eda9f")
[2.4.3 初始化:initializeBean()](#2.4.3 初始化:initializeBean() "#toc-a684e0c634ee69626fc544e2240798e3")
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 类型:
arduino
public class Dog {
private String name;
// 省略构造方法、getter 和 setter
}
在配置类中使用 @Bean
注解声明 singleton 作用域的 Bean(默认无需显式指定 @Scope("singleton")
):
typescript
@Configuration
public class AppConfig {
@Bean
public Dog singleDog() {
return new Dog("Singleton Dog");
}
}
在测试代码中,通过 Spring 容器两次获取 singleDog
实例并比较其哈希码:
csharp
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 的典型定义方式:
less
@Configuration
public class AppConfig {
@Bean
@Scope("prototype") // 显式指定原型作用域
public Dog prototypeDog() {
return new Dog();
}
}
该配置的核心特性体现为两点:实例化时机的延迟性 与生命周期管理的自主性 。与 singleton Bean 在容器启动阶段完成实例化不同,prototype Bean 仅在调用 getBean()
方法时触发实例化流程;更关键的是,Spring 容器对 prototype 实例的生命周期管理仅负责"创建"环节,而将"销毁"操作完全交由应用程序自行处理,容器不会调用 @PreDestroy
注解的方法或执行其他销毁回调。
为验证 prototype 作用域的实例唯一性,可通过对比多次获取的 Bean 哈希码实现。测试代码如下:
csharp
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: 123456
与 dog2: 789012
),直接证明每次获取操作均创建了全新实例。这种特性使其成为有状态组件 的理想选择------例如 Web 应用中的请求参数封装类(如 UserForm
),每个 HTTP 请求需独立存储用户输入数据,若使用 singleton 作用域将导致请求间状态污染,而 prototype 作用域通过实例隔离从根本上避免了此类问题。
核心结论:prototype 作用域通过"按需创建、实例隔离"的设计,为需要维护独立状态的组件提供了安全解决方案。在实际开发中,应明确区分有状态与无状态组件------对于工具类、服务层对象等无状态组件优先使用 singleton,而请求上下文、会话数据等有状态场景则需采用 prototype 作用域。
2.2.3request(请求)
在 Spring 容器中,request 作用域 的 Bean 可类比为快递服务中的产品生产逻辑:同一快递单内的产品保持一致,不同快递单则需重新生产。这意味着 Bean 实例的生命周期与单次 HTTP 请求强绑定,在请求发起时创建,请求完成后销毁,且在同一请求内多次获取的实例完全相同。
配置示例与核心特性
通过 @Scope("request")
注解可定义 request 作用域的 Bean。以下为 requestDog
的配置案例:
less
@Configuration
public class RequestScopeConfig {
@Bean
@Scope("request") // 声明为 request 作用域
public Dog requestDog() {
return new Dog(); // 每次新请求创建新实例
}
}
该配置的核心特性体现为:单次 HTTP 请求内唯一实例,请求结束自动销毁 。当客户端发起一次 HTTP 请求时,Spring 容器会创建 requestDog
的实例并缓存于请求上下文中,在此请求的处理流程(如 Controller → Service → Repository)中,无论通过 @Autowired
或 getBean()
多少次获取该 Bean,得到的都是同一个实例;而当请求响应完成后,该实例会被立即销毁,释放资源
特性验证与测试结果
通过对比同一请求与不同请求中 Bean 的哈希码,可直观验证 request 作用域的唯一性。例如在 Controller 中两次注入 requestDog
并打印其哈希码:
kotlin
@RestController
public class DogController {
@Autowired
private Dog requestDog1;
@Autowired
private Dog requestDog2;
@GetMapping("/test-request-scope")
public String testRequestScope() {
return "同一请求内实例哈希码:" + requestDog1.hashCode() + "," + requestDog2.hashCode();
}
}
测试结果显示 :同一请求内 requestDog1
与 requestDog2
的哈希码完全相同,证明二者为同一实例;而发起新请求后,哈希码会发生变化,表明新实例已被创建。
关键结论: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 配置代码
less
@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:
less
@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 实例并比较哈希码,可直观证明其共享特性。在不同用户会话中执行以下测试代码:
kotlin
@RestController
public class ScopeTestController {
@Autowired
private 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)
核心任务:通过构造函数创建对象毛坯(未设置属性)。
代码示例:
csharp
public class BeanLifeComponent {
private String name; // 初始null
private int age; // 初始0
public BeanLifeComponent() {
System.out.println("实例化:name=" + name + ", age=" + age);
}
}
输出 :实例化:name=null, age=0
源码对应 :AbstractAutowireCapableBeanFactory.createBeanInstance()
通过反射调用构造函数。
2.3.2属性赋值(Populate)
核心任务:注入依赖Bean及配置值。
代码示例:
kotlin
public class UserService {
@Autowired
private DogComponent dogComponent; // 注入依赖
}
源码对应 :AbstractAutowireCapableBeanFactory.populateBean()
通过类型/名称匹配注入依赖。
2.3.3初始化(Initialization)
执行顺序:Aware接口回调 → @PostConstruct → InitializingBean → init-method
代码示例:
typescript
@Component
public class InitDemo implements BeanNameAware {
@Override
public void setBeanName(String name) {
System.out.println("Aware回调:" + name);
}
@PostConstruct
public void postConstruct() {
System.out.println("执行@PostConstruct");
}
}
源码对应 :AbstractAutowireCapableBeanFactory.initializeBean()
串联初始化流程。
2.3.4使用(In Use)
Bean处于就绪状态,通过@Autowired
或getBean()
获取实例并调用业务方法:
typescript
@Autowired
private UserService userService;
public void process() {
userService.handleData(); // 使用Bean
}
2.3.5销毁(Destruction)
执行顺序:@PreDestroy → DisposableBean → destroy-method
代码示例:
csharp
@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()
ini
// 核心逻辑:解析类对象并反射创建实例
Class<?> beanClass = resolveBeanClass(mbd, beanName);
Constructor<?> ctor = beanClass.getDeclaredConstructor();
return ctor.newInstance(); // 反射创建对象
2.4.2 属性赋值:populateBean()
scss
// 核心逻辑:按名称/类型注入依赖
autowireByName(beanName, mbd, bw, pvs); // 按名称匹配
applyPropertyValues(beanName, mbd, bw, pvs); // 设置属性值
2.4.3 初始化:initializeBean()
scss
// 核心逻辑:执行初始化流程
invokeAwareMethods(beanName, bean); // Aware接口回调
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
invokeInitMethods(beanName, wrappedBean, mbd); // 初始化方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
3.小结
掌握Bean的作用域与生命周期,是理解Spring IoC容器设计思想的基础,也是解决线程安全、资源泄漏等问题的关键。建议结合本文案例代码调试,观察不同作用域下Bean实例的创建与销毁过程,加深理解。
今天的分享到这里就结束了,喜欢的小伙伴点点赞点点关注,你的支持就是对我最大的鼓励,大家加油!