Spring 中完整的 Scope 选项详解

Spring 中完整的 Scope 选项详解

Spring 的 scope 属性确实不止 singletonprototype 两个。根据应用类型和 Spring 生态的不同,一共有 8 种可选值。它们可以分为三类:核心作用域、Web 作用域、扩展作用域。

一、核心作用域(2 个)

这两个是 Spring 容器内置的基础作用域,适用于所有类型的应用。

作用域 说明
singleton 默认值,容器中只有一个实例,全局共享
prototype 每次获取都创建新实例
java 复制代码
@Component
@Scope("singleton")  // 默认,可省略
public class UserService { }

@Component
@Scope("prototype")
public class ShoppingCart { }

二、Web 作用域(4 个)

这 4 个作用域只在 Web 应用中有效,需要 WebApplicationContext 支持。

1. request

每个 HTTP 请求创建一个实例,请求结束后销毁。

java 复制代码
@Component
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class RequestContext {
    private String requestId;
    // ...
}

2. session

每个 HTTP Session 创建一个实例,Session 失效时销毁。

java 复制代码
@Component
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class UserSession {
    private User currentUser;
    // ...
}

3. application

每个 ServletContext 创建一个实例,整个 Web 应用共享。

java 复制代码
@Component
@Scope(value = "application", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class AppCounter {
    private AtomicInteger totalVisits = new AtomicInteger(0);
    // ...
}

4. websocket

每个 WebSocket 会话创建一个实例,连接关闭时销毁。Spring 5+ 支持。

java 复制代码
@Component
@Scope(value = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class WebSocketSessionBean {
    private String sessionId;
    // ...
}

三、扩展作用域(2 个)

这两个不在 Spring Framework 核心中,而是来自 Spring Cloud 或自定义实现。

5. refresh(Spring Cloud)

用于 Spring Cloud 的配置动态刷新。当配置中心(如 Nacos、Config Server)的配置变更时,被 @RefreshScope 标注的 Bean 会被重新创建,注入最新的配置值。

java 复制代码
@Component
@RefreshScope  // 等价于 @Scope("refresh")
public class ConfigurableBean {
    @Value("${app.timeout}")
    private int timeout;
}

当调用 /actuator/refresh 端点时,refresh 作用域的 Bean 会被销毁并重新创建,timeout 会更新为最新值。

6. globalSession(旧版 Portlet)

用于 Portlet 应用的全局会话作用域。在 Portlet 规范中,globalSession 表示跨所有 Portlet 的全局会话。Spring MVC 应用不使用这个作用域,它在 Spring 5 之后已经很少见。

xml 复制代码
<bean id="globalSessionBean" class="com.example.MyBean" scope="globalSession"/>

四、自定义作用域

除了以上 6 个内置作用域,Spring 还允许通过实现 Scope 接口定义自定义作用域。常见的自定义作用域有:

7. thread(线程作用域)

每个线程一个实例,常用于线程隔离的场景。

java 复制代码
public class ThreadScope implements Scope {
    private final ThreadLocal<Map<String, Object>> threadScope = 
        ThreadLocal.withInitial(HashMap::new);
    
    @Override
    public Object get(String name, ObjectFactory<?> objectFactory) {
        return threadScope.get().computeIfAbsent(name, k -> objectFactory.getObject());
    }
    
    @Override
    public Object remove(String name) {
        return threadScope.get().remove(name);
    }
    
    @Override
    public void registerDestructionCallback(String name, Runnable callback) {
    }
    
    @Override
    public Object resolveContextualObject(String key) {
        return null;
    }
    
    @Override
    public String getConversationId() {
        return Thread.currentThread().getName();
    }
}

注册:

java 复制代码
@Configuration
public class ScopeConfig {
    @Bean
    public CustomScopeConfigurer customScopeConfigurer() {
        CustomScopeConfigurer configurer = new CustomScopeConfigurer();
        configurer.addScope("thread", new ThreadScope());
        return configurer;
    }
}

使用:

java 复制代码
@Component
@Scope("thread")
public class ThreadScopedBean {
}

8. 其他自定义作用域

根据业务需要,还可以定义更多作用域,例如:

  • tenant:多租户场景,每个租户一个实例
  • batch:批处理任务,每次批处理一个实例
  • conversation:Web 对话作用域(类似 Seam 框架的 conversation)

五、8 个 Scope 汇总表

序号 作用域 来源 实例范围 适用场景
1 singleton Spring 核心 整个容器一个 无状态服务
2 prototype Spring 核心 每次获取新实例 有状态对象
3 request Spring Web 每个 HTTP 请求一个 请求级数据
4 session Spring Web 每个 Session 一个 用户会话数据
5 application Spring Web 每个 ServletContext 一个 全局共享数据
6 websocket Spring WebSocket 每个 WebSocket 连接一个 WebSocket 会话
7 refresh Spring Cloud 配置刷新时重建 动态配置
8 globalSession Portlet 全局会话一个 Portlet 应用(旧版)

六、作用域的选择依据

场景 推荐作用域 理由
Service、Dao、Controller singleton 无状态,共享安全
有状态的对象 prototype 隔离状态
请求上下文 request 每个请求独立
用户登录信息 session 每个用户独立
全局计数器 application 全应用共享
WebSocket 会话 websocket 每个连接独立
动态配置 refresh 配置变更时刷新
线程隔离 自定义 thread 每个线程独立

七、注意事项

1. Web 作用域需要代理

requestsessionapplicationwebsocket 作用域的 Bean 注入到 singleton Bean 时,必须配置 proxyMode,否则会报 Scope 'xxx' is not active 错误。

2. 作用域名称大小写

Spring 的作用域名称是区分大小写 的。singleton 不能写成 Singletonprototype 不能写成 Prototype

3. 自定义作用域需要注册

自定义作用域必须先通过 CustomScopeConfigurer 注册到容器,才能在 @Scope 中使用。

4. prototype 的销毁不归 Spring 管

Spring 只创建 prototype Bean,不管理销毁。@PreDestroyDisposableBean 对 prototype Bean 不生效。

5. refresh 依赖 Spring Cloud

refresh 作用域不是 Spring Framework 自带的,需要引入 Spring Cloud Context 依赖。

八、总结

分类 作用域 数量
核心作用域 singletonprototype 2
Web 作用域 requestsessionapplicationwebsocket 4
扩展作用域 refreshglobalSession 2
自定义作用域 threadtenant 不限

Spring 一共提供了 8 种可选的作用域 (6 个内置 + 2 个扩展),另外还支持自定义。日常开发中最常用的是 singletonprototype,Web 项目中会用到 requestsession,Spring Cloud 项目中会用到 refresh。理解每种作用域的实例范围和生命周期,是设计高质量 Spring 应用的基础。

相关推荐
hai_android1 小时前
Android MeasureSpec 详解
android·java·kotlin
LEE1 小时前
前端转型全栈 03:接口失败也返回 200,OpenAPI 契约与错误码怎么定
前端·后端·全栈
打工仔折腾 AI2 小时前
用 Docker 部署 Excalidraw 手绘白板并配置固定公网访问的完整实践
人工智能·后端·python
山岚的运维笔记2 小时前
mysql 专业笔记 -- 第 36 章:MySQL 管理
运维·数据库·笔记·后端·mysql·oracle·dba
掘金者阿豪2 小时前
Oracle 迁移金仓,50 个存储过程到底要改多少?聊聊实际改造中的几个问题
后端
梅梅绵绵冰2 小时前
大模型应用开发-SpringAI框架
spring·ai
大白802 小时前
iOS 内存深度解析:ARC 到底是怎么管理对象生命周期的
后端
焦玉全2 小时前
Redis Lua 脚本实战:从入门到精通(Java 版)
后端
阳光宅男@李光熠2 小时前
【电子通识】一起学习TDK的EMC基础——电池兼容设计方法概述
java·前端·数据库