在 Spring 应用中,Bean 的生命周期和作用域是对象管理的核心机制。
它们决定了Bean 的创建方式、存活时间以及作用范围。深入理解这些机制,可以避免内存泄漏、优化资源利用,并设计出更高效的 Spring 应用。
一、Bean 的生命周期:从诞生到消亡
SpringBean 的生命周期是指从Bean 创建到销毁的完整过程。Spring 提供了多种方式来管理 Bean 的生命周期,包括初始化方法、销毁方法、生命周期回调接口等。
1.1 生命周期流程图
实例化 → 属性注入 → 初始化 → 使用中 → 销毁
1.实例化(Instantiation)
Spring 容器创建 Bean 的实例。
2.属性赋值(Populate Properties)
Spring 容器根据配置文件或注解,为 Bean 注入依赖。
3.初始化(Initialization)
在 Bean 可用之前,Spring 会执行初始化操作(可通过@PostConstruct、InitializingBean或init-method实现)。
4.使用(Usage)
Bean 处于运行状态,可供应用程序调用和使用。
5.销毁(Destruction)
当容器关闭时,Spring 会执行销毁回调(可通过@PreDestroy、DisposableBean或destroy-method实现)。
1.2 初始化与销毁的三种方式
方式 1:注解驱动(推荐)
通过@PostConstruct和@PreDestroy管理生命周期。
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;@Component // 该类被 Spring 作为 Bean 进行管理
public class DatabaseConnector {@PostConstructpublic void connect() {System.out.println("数据库连接已建立");}@PreDestroypublic void disconnect() {System.out.println("数据库连接已关闭");}
}
注解说明
• @Component
声明该类为 Spring 管理的 Bean。
• @PostConstruct
在 Bean 初始化后自动执行。
• @PreDestroy
在 Bean 销毁前执行。
优势
• 代码简洁,无侵入性。
• 无需实现特定接口。
方式 2:实现 Spring 接口
通过InitializingBean和DisposableBean接口管理生命周期。
Spring 提供了InitializingBean(初始化)和DisposableBean(销毁)两个接口,它们分别包含:
• afterPropertiesSet()
• destroy()
示例:
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;@Component
public class MyBean implements InitializingBean, DisposableBean {public MyBean() {System.out.println("1. Bean 实例化");}@Overridepublic void afterPropertiesSet() {System.out.println("2. Bean 初始化(afterPropertiesSet)");}@Overridepublic void destroy() {System.out.println("3. Bean 销毁(destroy)");}
}
注解/接口说明
• InitializingBean接口:提供afterPropertiesSet()方法,Spring 在 Bean 初始化后调用。
• DisposableBean接口:提供destroy()方法,Spring 在 Bean 销毁前调用。
适用场景
• 需要与 Spring 早期版本兼容。
• 明确的生命周期方法定义。
方式 3:XML/Java 显式配置
通过init-method和destroy-method指定初始化和销毁方法。
在@Bean方法或 XML 配置中,也可以手动指定初始化和销毁方法:
@Configuration
public class AppConfig {@Bean(initMethod = "init", destroyMethod = "cleanup")public FileProcessor fileProcessor() {return new FileProcessor();}
}public class FileProcessor {public void init() {System.out.println("文件处理器初始化完成");}public void cleanup() {System.out.println("临时文件已清理");}
}
所用配置
• initMethod=“init”:指定初始化方法,在 Bean 创建后调用。
• destroyMethod=“cleanup”:指定销毁方法,在 Bean 销毁前调用。
适用场景
• 无法修改第三方库的源码。
• 需要动态指定初始化逻辑。
二、Bean 的作用域:控制对象的作用范围
Spring 支持6 种作用域,其中4 种专为 Web 应用设计。最常用的作用域是Singleton和Prototype。
2.1 核心作用域详解
1. Singleton(单例)
特点:
• 默认作用域。
• 适用于无状态 Bean(如 Service、DAO)。
• 容器启动时创建(可配置懒加载)。
• 全局唯一,整个 Spring 容器中只有一个 Bean 实例。
示例:
import org.springframework.stereotype.Component;@Component // 默认作用域是 Singleton
public class SingletonBean {public SingletonBean() {System.out.println("SingletonBean 被创建");}
}
验证单例作用域
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
SingletonBean bean1 = context.getBean(SingletonBean.class);
SingletonBean bean2 = context.getBean(SingletonBean.class);System.out.println(bean1 == bean2); // true
说明
• @Component 将类声明为 Spring Bean。
• 默认作用域是Singleton,即整个容器中只有一个实例。
2. Prototype(原型作用域,每次获取都创建新实例)
特点:
• 每次获取getBean(),都会创建一个新实例。
• 适用于有状态的 Bean,如需要频繁创建的新对象,如DTO、会话上下文。
示例:
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;@Component
@Scope("prototype") // 设置为 Prototype 作用域,每次获取都会创建新实例
public class PrototypeBean {public PrototypeBean() {System.out.println("PrototypeBean 被创建");}
}
验证 Prototype 作用域
PrototypeBean bean1 = context.getBean(PrototypeBean.class);
PrototypeBean bean2 = context.getBean(PrototypeBean.class);System.out.println(bean1 == bean2); // false
注解说明
• @Scope(“prototype”)
每次获取 Bean 时,Spring 都会创建新实例。
3. Web 作用域

示例 request 作用域:
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;@Component
@Scope("request") // 作用域设置为 request,每个请求都会创建新 Bean
public class RequestScopedBean {public RequestScopedBean() {System.out.println("RequestScopedBean 被创建");}
}
注解说明
• @Scope(“request”)
每个 HTTP 请求都会创建新的 Bean 实例,适用于 Web 应用。
2.2 作用域配置陷阱与解决方案
问题:
单例 Bean 注入原型 Bean 时,原型失效。
原因:
单例 Bean 初始化时已固定依赖的原型实例。
解决方案
• 使用方法注入(@Lookup)。
• 通过ObjectFactory延迟获取。
• 设置代理模式(proxyMode = ScopedProxyMode.TARGET_CLASS)。
@Service
public class OrderService {@Autowiredprivate ObjectFactory<ShoppingCart> cartFactory;public void checkout() {ShoppingCart cart = cartFactory.getObject(); // 每次获取新实例// ...}
}
三、实战:生命周期与作用域的综合应用
场景:数据库连接池管理
@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class ConnectionPool {private List<Connection> connections;@PostConstructpublic void init() {System.out.println("初始化连接池...");connections = Collections.synchronizedList(new ArrayList<>());// 创建初始连接}public Connection getConnection() {return connections.remove(0);}@PreDestroypublic void destroy() {System.out.println("关闭所有连接...");connections.forEach(Connection::close);}
}
设计要点
• 单例作用域管理共享资源
• 初始化时建立连接池
• 销毁时安全释放资源
四、总结与进阶
4.1 关键知识点回顾
• 生命周期管理:通过注解、接口、配置三种方式控制 Bean 的初始化和销毁
• 作用域选择:根据对象状态和使用场景选择合适的作用域
• Web 作用域:合理使用Request/Session作用域处理 Web 层数据
