@Scope
和 @RefreshScope
是 Spring 框架中用于控制 Bean 生命周期和作用域的核心注解,分别解决“Bean 的作用域管理”和“动态配置刷新”问题。以下从注解定义、源码解析、核心功能、使用场景及区别对比展开详细说明。
一、@Scope
详解
1. 注解定义与源码解析
@Scope
位于 org.springframework.context.annotation
包中,其源码定义如下(简化版):
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
/**
* 作用域名称(默认 "singleton")
*/
String value() default "singleton";
/**
* 作用域代理模式(默认 "no",可选 "target_class" 或 "interfaze")
*/
String proxyMode() default "no";
}
关键特性:
- 定义 Bean 的作用域(生命周期范围),决定 Bean 实例的创建和销毁时机。
- 支持的作用域类型包括:
singleton
(单例)、prototype
(原型)、request
(请求)、session
(会话)、application
(应用)等。 proxyMode
用于解决作用域 Bean 的依赖注入问题(如单例 Bean 依赖原型 Bean 时,需通过代理延迟获取)。
2. 核心功能:控制 Bean 的生命周期
Spring 容器根据 @Scope
的值管理 Bean 的生命周期,核心逻辑如下:
(1)singleton
(单例,默认)
- 生命周期:Bean 在容器启动时创建,容器关闭时销毁(全局唯一实例)。
- 适用场景:无状态 Bean(如工具类、服务层组件)。
示例:
@Service
@Scope("singleton") // 默认可省略
public class UserService {
// 单例实例,全局共享
}
(2)prototype
(原型)
- 生命周期:每次通过
getBean()
获取 Bean 时创建新实例,容器不管理其销毁。 - 适用场景:有状态 Bean(如需要保存用户会话状态的工具类)。
示例:
@Service
@Scope("prototype")
public class UserSession {
private String userId;
// 每次获取新实例,userId 可独立设置
}
(3)request
(请求作用域,Web 环境)
- 生命周期:Bean 在 HTTP 请求进入时创建,请求结束时销毁(仅存活于当前请求)。
- 适用场景:需要保存请求级状态的对象(如请求参数处理器)。
示例(需配合 DispatcherServlet
):
@Controller
@Scope("request")
public class RequestController {
@Autowired
private HttpServletRequest request; // 注入当前请求对象
}
(4)session
(会话作用域,Web 环境)
- 生命周期:Bean 在用户会话创建时创建,会话超时或销毁时销毁(存活于整个会话)。
- 适用场景:需要保存用户会话状态的对象(如购物车)。
示例:
@Controller
@Scope("session")
public class CartController {
@Autowired
private HttpSession session; // 注入当前会话对象
}
(5)application
(应用作用域)
- 生命周期:Bean 在 ServletContext 初始化时创建,ServletContext 销毁时销毁(全局单例,作用域大于
singleton
)。 - 适用场景:需要全局共享且与 Servlet 上下文绑定的对象(如应用配置)。
3. 作用域代理(proxyMode
)的实现
当单例 Bean 依赖原型 Bean 时,直接注入会导致原型 Bean 仅创建一次(单例 Bean 缓存了原型 Bean 的引用)。此时需通过 proxyMode
生成代理对象,延迟获取最新实例:
示例:
@Service
@Scope("singleton")
public class OrderService {
// 依赖原型 Bean(每次调用 getPaymentService() 获取新实例)
@Autowired
private PaymentService paymentService; // 实际为代理对象
}
@Service
@Scope(value = "prototype", proxyMode = ScopedProxyMode.TARGET_CLASS) // 生成 CGLIB 代理
public class PaymentService {
// 每次调用方法时,代理会重新获取原型实例
}
关键类:
ScopedProxyFactoryBean
:生成作用域代理的核心类,通过 CGLIB 或 JDK 动态代理实现。
二、@RefreshScope
详解
1. 注解定义与源码解析
@RefreshScope
是 Spring Cloud 提供的扩展注解(位于 org.springframework.cloud.context.scope.refresh
包),其源码定义如下(简化版):
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RefreshScope {
/**
* 作用域名称(默认 "refresh")
*/
String value() default "refresh";
/**
* 是否延迟初始化(默认 false)
*/
boolean lazyInit() default false;
}
关键特性:
- 标记 Bean 为“可刷新作用域”,当配置中心的配置变更时,Bean 会被销毁并重新创建,从而加载新配置。
- 依赖 Spring Cloud Config 或
@ConfigurationProperties
实现动态配置加载。
2. 核心功能:动态配置刷新
@RefreshScope
的核心作用是支持配置热更新,其工作流程如下:
(1)配置变更触发刷新
当配置中心(如 Spring Cloud Config Server)的配置文件(application.yml
)发生变更时,通过以下方式触发刷新:
- 手动触发:向 Spring Cloud Config Server 发送 POST 请求(如
/actuator/refresh
)。 - 自动触发:通过
@Scheduled
定时轮询配置中心,或结合 Webhook 自动检测变更。
(2)刷新过程
- 标记刷新作用域:
@RefreshScope
的 Bean 被注册到RefreshScope
作用域中(由RefreshScope
管理生命周期)。 - 销毁旧实例:刷新时,
RefreshScope
销毁当前 Bean 实例,并从容器中移除。 - 创建新实例:重新调用 Bean 的构造方法和初始化方法(如
@PostConstruct
),加载最新的配置。
3. 典型使用场景与示例
(1)动态配置加载
当 @ConfigurationProperties
绑定的配置变更时,@RefreshScope
确保 Bean 使用最新配置:
示例:
// 配置类:绑定 application.yml 中的配置
@Data
@Component
@ConfigurationProperties(prefix = "app")
@RefreshScope // 配置变更时刷新
public class AppConfig {
private String env;
private Integer timeout;
}
// 服务类:使用动态配置
@Service
public class OrderService {
@Autowired
private AppConfig appConfig; // 每次刷新后使用最新配置
public void createOrder() {
System.out.println("当前环境:" + appConfig.getEnv()); // 配置变更后输出新值
}
}
(2)微服务配置热更新
在微服务架构中,@RefreshScope
配合配置中心实现“零停机”配置更新:
# application.yml(配置中心)
app:
env: dev
timeout: 3000
当修改 app.env
为 prod
并触发刷新后,所有 @RefreshScope
标记的 Bean 会自动使用 prod
环境的配置。
4. 源码实现细节与关键类
@RefreshScope
的核心实现依赖以下类:
(1)RefreshScope
- 作用:管理可刷新 Bean 的生命周期,提供
refresh()
方法触发刷新。 - 关键方法:
get(String name, ObjectFactory<?> objectFactory)
:获取 Bean 实例(首次创建或刷新后重新创建)。refreshAll()
:刷新所有属于该作用域的 Bean。
(2)RefreshScopeBeanDefinitionRegistrar
- 作用:注册
@RefreshScope
Bean 的定义,将其标记为RefreshScope
作用域。
(3)ConfigurationPropertiesBindingPostProcessor
- 作用:结合
@ConfigurationProperties
,在刷新时重新绑定配置属性到 Bean。
三、@Scope
与 @RefreshScope
的区别对比
特性 | @Scope | @RefreshScope |
---|---|---|
所属框架 | Spring 核心 | Spring Cloud 扩展 |
核心目标 | 控制 Bean 的生命周期(作用域) | 支持配置动态刷新(重新创建 Bean) |
作用域类型 | 单例、原型、请求、会话等 | 仅“刷新作用域”(与配置变更绑定) |
生命周期触发条件 | 容器启动/关闭、请求/会话开始/结束 | 配置中心配置变更(手动或自动触发) |
典型场景 | 无状态/有状态 Bean 的生命周期管理 | 微服务配置热更新、动态属性绑定 |
依赖关系 | Spring 核心功能 | 依赖 Spring Cloud Config 或配置中心 |
四、注意事项与常见问题
1. @Scope
的注意事项
- 原型 Bean 的依赖注入:单例 Bean 依赖原型 Bean 时,需通过
proxyMode
生成代理,否则原型 Bean 仅创建一次。 - Web 作用域的限制:
request
和session
作用域仅在 Web 环境(如 Spring MVC)中有效,否则会抛出异常。
2. @RefreshScope
的注意事项
- 配置中心的集成:需先集成 Spring Cloud Config Server 或使用
@ConfigurationProperties
绑定本地配置。 - 刷新的性能影响:频繁刷新可能导致 Bean 重复创建,需评估配置变更频率。
- 依赖注入的顺序:刷新时 Bean 的依赖(如数据库连接)需支持重新初始化,避免状态残留。
3. 性能优化建议
- 对于
@Scope("prototype")
的 Bean,避免在方法中执行耗时操作(如文件 IO),减少实例创建开销。 - 对于
@RefreshScope
的 Bean,尽量减少刷新频率(如通过@Scheduled
定时刷新而非实时轮询)。
五、总结
@Scope
和 @RefreshScope
是 Spring 中管理 Bean 生命周期和动态配置的核心注解:
@Scope
控制 Bean 的作用域(如单例、原型、请求等),适用于常规的生命周期管理场景。@RefreshScope
是 Spring Cloud 的扩展,支持配置动态刷新,适用于微服务架构中的热更新场景。
理解它们的源码(如 RefreshScope
的代理机制、@Scope
的作用域注册)和使用场景,有助于开发者编写更灵活、可维护的 Spring 应用。