bigywater.tech
Spring · 126

@RefreshScope 的原理与代价

@RefreshScope 到底刷新了谁、没刷新谁?为什么我的 @Value 还是旧值?改了一个无关的配置也会重建 bean 吗?刷新之后第一个请求会变慢吗?这篇在 Spring Cloud 2025.1.3 上用五种读取配置的方式对比同一个 app.msg。

2 个变了
五种读取配置的 bean 里,刷新后只有 @RefreshScope 的 bean 和 setter 绑定的 @ConfigurationProperties 变成新值
什么都没改也重建
POST /actuator/refresh 返回 [] 时 @RefreshScope 的 bean 仍被销毁重建
408 ms
构造函数睡 400 ms 的 @RefreshScope bean,刷新后第一次访问的耗时

谁被刷新

实测 · 本机执行输出
  启动后 GET /v → @RefreshScope 的 @Value=v1,该 bean 被调用的次数(实例内计数)=1;普通单例的 @Value=v1;单例在构造时复制的值=v1;@ConfigurationProperties(setter)=v1;@ConfigurationProperties(record)=v1;RefreshBean 创建过 1 次、销毁过 0 次
  文件改成 app.msg=v2,还没有刷新,GET /v → @RefreshScope 的 @Value=v1,该 bean 被调用的次数(实例内计数)=2;普通单例的 @Value=v1;单例在构造时复制的值=v1;@ConfigurationProperties(setter)=v1;@ConfigurationProperties(record)=v1;RefreshBean 创建过 1 次、销毁过 0 次
  POST /actuator/refresh → 200 ["app.msg"]
  刷新之后 GET /v → @RefreshScope 的 @Value=v2,该 bean 被调用的次数(实例内计数)=1;普通单例的 @Value=v1;单例在构造时复制的值=v1;@ConfigurationProperties(setter)=v2;@ConfigurationProperties(record)=v1;RefreshBean 创建过 2 次、销毁过 1 次

@RefreshScope bean 与 setter 绑定的 @ConfigurationProperties;单例的 @Value、构造时复制的值、record 绑定都不变。

粗粒度

实测 · 本机执行输出
  只新增 other.unrelated=x,POST /actuator/refresh → 200 ["other.unrelated"]
  GET /v → @RefreshScope 的 @Value=v2,该 bean 被调用的次数(实例内计数)=1;普通单例的 @Value=v1;单例在构造时复制的值=v1;@ConfigurationProperties(setter)=v2;@ConfigurationProperties(record)=v1;RefreshBean 创建过 3 次、销毁过 2 次
  什么都没改,再 POST /actuator/refresh → 200 []
  GET /v → @RefreshScope 的 @Value=v2,该 bean 被调用的次数(实例内计数)=1;普通单例的 @Value=v1;单例在构造时复制的值=v1;@ConfigurationProperties(setter)=v2;@ConfigurationProperties(record)=v1;RefreshBean 创建过 4 次、销毁过 3 次

每次 refresh 销毁所有 @RefreshScope bean,与改了哪个 key 无关。

代价

实测 · 本机执行输出
  启动后第一次 GET /v 53 ms,第二次 2 ms
  POST /actuator/refresh 本身耗时 66 ms(返回 ["app.msg"])
  刷新后第一次 GET /v 408 ms(要重新创建 bean),第二次 3 ms

启动时提前创建,刷新后在下一次访问时重建,请求线程承担初始化耗时。

分步演示

RefreshScope
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK 21.0.12(Homebrew) / Spring Boot 4.0.8(Spring Framework 7.0.9、Tomcat 11.0.24) / Spring Cloud 2025.1.3;用 javac 编译、java 直接运行,依赖由 Maven 从 Maven Central 解析;数字每次运行会有小幅抖动。配置源是外部文件 ./extra.properties(spring.config.import=optional:file:./extra.properties),不用 Config Server;刷新用 actuator 的 refresh 端点(POST);耗时是一次本机请求的整体耗时
    • 没有验证:Config Server 加 Spring Cloud Bus 的广播刷新;record 绑定的 @ConfigurationProperties 为什么不会重新绑定(只观察到结果);@RefreshScope 的代理(CGLIB)对并发请求的影响;刷新期间正在处理中的请求拿到的是旧实例还是新实例;DataSource、Kafka 等基础设施 bean 放进 @RefreshScope 后连接的泄露;spring.cloud.refresh.enabled=false 与 extra-refreshable;@Scheduled 等定时任务在刷新后的行为
    京ICP备2026067502号-1京公网安备11010502063487号