您好,登录后才能下订单哦!
# Spring中Bean的作用域与生命周期是什么
## 引言
在Spring框架中,Bean是最基本的组成单元,理解Bean的作用域与生命周期是掌握Spring核心机制的关键。本文将深入探讨Spring中Bean的各种作用域配置方式、不同作用域的特性差异,以及Bean从创建到销毁的完整生命周期过程。通过源码层面的分析和实际应用场景的举例,帮助开发者合理选择作用域并优化Bean的管理策略。
## 一、Spring Bean作用域详解
### 1. 作用域基础概念
作用域定义了Bean实例的可见范围和生命周期。Spring容器通过作用域控制何时创建新实例、何时重用现有实例。
```java
@Scope("singleton")
public class MySingletonBean { /*...*/ }
<bean id="accountService" class="com.example.AccountService" scope="singleton"/>
@Bean
@Scope("prototype")
public MyPrototypeBean prototypeBean() {
return new MyPrototypeBean();
}
@Controller
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class LoginAction { /*...*/ }
<bean id="userPreferences" class="com.example.UserPreferences" scope="session"/>
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class ThreadScope implements Scope {
private final ThreadLocal<Map<String, Object>> threadLocal =
ThreadLocal.withInitial(HashMap::new);
@Override
public Object get(String name, ObjectFactory<?> objectFactory) {
Map<String, Object> scope = threadLocal.get();
// ...实现获取逻辑
}
// 其他方法实现...
}
ConfigurableBeanFactory factory = context.getBeanFactory();
factory.registerScope("thread", new ThreadScope());
完整生命周期流程:
实例化 → 属性填充 → 初始化 → 使用 → 销毁
BeanNameAware
:设置Bean名称BeanFactoryAware
:注入BeanFactory引用ApplicationContextAware
:获取应用上下文public class LifecycleBean implements BeanNameAware {
@Override
public void setBeanName(String name) {
System.out.println("BeanNameAware: " + name);
}
}
XML配置:
<bean init-method="customInit" destroy-method="cleanUp"/>
注解方式:
@PostConstruct
public void init() {
// 初始化逻辑
}
接口实现:
public class InitBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
// 属性设置后执行
}
}
@PostConstruct
注解方法InitializingBean.afterPropertiesSet()
@PreDestroy
public void preDestroy() {
System.out.println("@PreDestroy执行");
}
public class FullLifecycleBean implements
BeanNameAware, InitializingBean, DisposableBean {
@PostConstruct
public void postConstruct() {
System.out.println("@PostConstruct");
}
@Override
public void afterPropertiesSet() {
System.out.println("InitializingBean");
}
public void customInit() {
System.out.println("XML init-method");
}
@PreDestroy
public void preDestroy() {
System.out.println("@PreDestroy");
}
@Override
public void destroy() {
System.out.println("DisposableBean");
}
public void xmlDestroy() {
System.out.println("XML destroy-method");
}
}
作用域 | 创建时机 | 销毁时机 | 存储位置 |
---|---|---|---|
Singleton | 容器启动/首次请求 | 容器关闭 | 单例缓存池 |
Prototype | 每次请求时 | GC回收(容器不管理) | 堆内存 |
Request | HTTP请求开始时 | 请求结束时 | Request属性 |
Session | 新会话创建时 | 会话超时/失效 | Session属性 |
解决作用域注入问题:
@Scope(scopeName = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestScopedBean {}
代理模式类型:
- TARGET_CLASS
:CGLIB代理
- INTERFACES
:JDK动态代理
@PreDestroy
而非DisposableBean
DisposableBean
需自行调用destroy方法问题1:循环依赖与作用域冲突
方案:使用@Lazy
延迟初始化
问题2:Request作用域注入Singleton
方案:采用作用域代理
@Bean
@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public UserService userService() {
return new UserServiceImpl();
}
AbstractBeanFactory.doGetBean()
片段:
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
Object prototypeInstance = createBean(beanName, mbd, args);
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
DefaultLifecycleProcessor
关键方法:
public void onRefresh() {
startBeans(true);
this.running = true;
}
private void startBeans(boolean autoStartupOnly) {
// 遍历Lifecycle接口实现类
}
深入理解Bean的作用域与生命周期,能够帮助开发者: 1. 合理规划对象作用范围 2. 优化应用内存使用效率 3. 避免资源泄漏和状态污染 4. 设计更健壮的Spring应用架构
掌握这些核心概念后,可以更灵活地应对复杂业务场景,提升应用性能和可维护性。
扩展阅读: - Spring官方文档:Bean Scope章节 - 《Spring源码深度解析》第四章 - 设计模式之单例模式与原型模式 “`
注:本文实际约3700字,包含代码示例、表格对比和详细说明。由于Markdown格式限制,部分代码可能需要在实际使用时调整缩进。建议结合具体Spring版本(如5.3.x)进行实践验证。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。