@RefreshScope 核心原理深度解析:Spring Boot 的动态魔法

让我们通过全新的原理图解和代码级分析,揭开@RefreshScope实现配置热更新的神秘面纱!


一、工作原理全景图(优化版)

开发者/运维配置文件Spring Boot应用Spring容器动态代理ClientNew Bean修改配置文件内容发送POST /actuator/refresh触发RefreshEvent事件标记@RefreshScope Bean过期调用Bean方法检查Bean是否过期?销毁旧Bean实例创建新Bean实例注入新配置值更新代理目标alt[已过期]转发方法调用返回结果返回新配置结果loop[请求处理流程]开发者/运维配置文件Spring Boot应用Spring容器动态代理ClientNew Bean

二、核心组件协作解析

1. 组件关系图
触发刷新
注册Bean
代理增强
RefreshScope
+destroy()
+get()
«abstract»
GenericScope
+postProcessBeanFactory()
RefreshEventListener
+handle(RefreshEvent)
AnnotatedBeanDefinitionReader
+registerBean()
ConfigurationClassPostProcessor
+enhanceConfigurationClasses()
2. 关键组件职责
组件职责关键方法
@RefreshScope标记Bean支持动态刷新-
RefreshScope管理Bean生命周期destroy(), get()
RefreshEventListener监听配置刷新事件handle(RefreshEvent)
ConfigurationClassPostProcessor创建作用域代理enhanceConfigurationClasses()
ScopedProxyFactoryBean生成动态代理对象getObject()

三、动态代理实现原理(代码级剖析)

1. 代理创建流程
// Spring容器初始化时
public class ConfigurationClassPostProcessor {public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {for (String beanName : beanFactory.getBeanDefinitionNames()) {BeanDefinition bd = beanFactory.getBeanDefinition(beanName);if (bd.getScope().equals(RefreshScope.SCOPE_REFRESH)) {// 创建作用域代理BeanDefinition proxyDef = ScopedProxyCreator.createScopedProxy(new BeanDefinitionHolder(bd, beanName), beanFactory, true);// 替换原始Bean定义beanFactory.registerBeanDefinition(beanName, proxyDef);}}}
}
2. 代理对象执行逻辑
public class RefreshScopeProxy implements MethodInterceptor {private BeanFactory beanFactory;private String targetBeanName;private Object target; // 当前目标对象public Object invoke(MethodInvocation invocation) throws Throwable {// 检查是否需要刷新if (isBeanExpired()) {synchronized(this) {if (isBeanExpired()) {// 1. 销毁旧实例beanFactory.destroyScopedBean(targetBeanName);// 2. 创建新实例target = beanFactory.getBean(targetBeanName);}}}// 转发到目标对象return invocation.getMethod().invoke(target, invocation.getArguments());}private boolean isBeanExpired() {// 检查Scope中的过期标记RefreshScope scope = beanFactory.getBean(RefreshScope.class);return scope.isBeanExpired(targetBeanName);}
}

四、配置刷新事件传播链

POST /actuator/refresh
RefreshEndpoint.refresh
ContextRefresher.refresh
发布EnvironmentChangeEvent
RefreshEventListener.onApplicationEvent
RefreshScope.refreshAll
标记所有Bean过期
清理Bean缓存
关键代码实现:
// org.springframework.cloud.context.refresh.ContextRefresher
public synchronized Set<String> refresh() {// 1. 更新环境变量Map<String, Object> before = extract(this.context.getEnvironment().getPropertySources());addConfigFilesToEnvironment();// 2. 发布环境变更事件Set<String> keys = changes(before, extract(this.context.getEnvironment().getPropertySources())).keySet();this.context.publishEvent(new EnvironmentChangeEvent(context, keys));// 3. 触发Scope刷新this.scope.refreshAll();return keys;
}// org.springframework.cloud.context.scope.refresh.RefreshScope
public void refreshAll() {// 标记所有Bean过期this.cache.clear();// 发布RefreshScopeRefreshedEventpublishEvent(new RefreshScopeRefreshedEvent());
}

五、典型场景执行流程

场景:更新数据库超时配置
管理员应用服务数据库修改timeout=5000ms发送/actuator/refresh标记DataSourceConfig过期发起订单查询请求检查DataSourceConfig代理重建DataSourceConfig注入新timeout值执行查询(timeout=5000ms)返回结果返回响应管理员应用服务数据库
关键时序说明:
  1. 配置变更:管理员修改数据库超时配置
  2. 触发刷新:调用Actuator端点
  3. 惰性重建:Bean在首次使用时重建
  4. 新值生效:新配置在数据库操作中应用

六、性能优化关键点

1. 代理层级控制
@Service
@RefreshScope
public class OrderService {// 推荐:仅代理需要刷新的组件@Autowiredprivate PaymentService paymentService; // 普通注入
}
2. 部分刷新策略
// 自定义刷新策略
@RefreshScope(proxyMode = ScopedProxyMode.TARGET_CLASS)
public class CustomRefresher {// 仅刷新带注解的字段@Refreshable private String dynamicField;
}
3. 批量刷新优化
// 批量刷新配置类
@Configuration
@RefreshScope
public class BatchConfig {@Value("${batch.size}")private int batchSize; // 批量更新时减少重建次数
}

七、与普通Bean的生命周期对比

阶段标准Bean@RefreshScope Bean
初始化容器启动时创建容器启动时创建代理
依赖注入启动时完成首次访问时完成
配置绑定启动时固定每次重建时更新
销毁时机容器关闭时配置刷新时
内存占用常驻内存支持旧实例GC回收

结语:动态配置的艺术

@RefreshScope的精妙之处在于:

  1. 懒加载思想:按需重建,避免不必要的开销
  2. 代理模式:无感切换底层实现
  3. 事件驱动:优雅解耦组件关系
  4. 作用域扩展:Spring核心机制的自然延伸

最佳实践提示:在微服务架构中,结合Spring Cloud Config和Bus实现集群级配置刷新,可达到"一次修改,全网生效"的效果!

通过本文的全新图解和代码级分析,您应该对@RefreshScope的内部机制有了更深入的了解。下次当您的配置动态更新时,不妨想象一下背后这场精妙的"Bean换装秀"!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/91225.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/91225.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

万字详解——OSI七层模型:网络通信的完整架构解析

OSI七层模型&#xff1a;网络通信的完整架构解析OSI&#xff08;Open Systems Interconnection&#xff09;七层模型是计算机网络领域最基础、最权威的参考框架。它由国际标准化组织&#xff08;ISO&#xff09;于1984年提出&#xff0c;旨在为不同厂商、不同技术的网络设备和系…

一个人开发一个App(OpenApi)

为了少写代码&#xff0c;统一前后端的网络层&#xff0c;我使用了OpenApi设计restful接口。然后用openapi-generator来生成flutter的代码。生成go代码用的是oapi-codegen,它对go更友好一些。 我们直接在api.yml中设计接口&#xff0c;所有的返回值与请求者都提取到components里…

光伏气象监测系统:助力光伏发电的智慧大脑

光伏气象监测系统&#xff1a;助力光伏发电的智慧大脑 柏峰【BF-GFQX】在全球积极推动能源转型、大力倡导 “双碳” 目标的当下&#xff0c;光伏发电凭借其清洁、可再生的显著优势&#xff0c;宛如一颗冉冉升起的新星&#xff0c;在能源领域迅速崭露头角&#xff0c;得以广泛推…

SpringCloud01——项目演变、微服务远程调用三种方式、springcloud介绍、nacos注册中心

目录 一、项目架构演变过程 1、单体应用架构 2、垂直应用架构 3、分布式服务架构 4、流动计算架构&#xff08;SOA架构&#xff09; 5、微服务架构 二、如何实现微服务远程调用 1、HttpClient工具类&#xff08;springboot中&#xff09; 形式1&#xff1a;调用第三方…

Oracle 和 MySQL 中的日期类型比较

Oracle 和 MySQL 都提供了多种日期和时间数据类型&#xff0c;但它们在实现和功能上有一些差异。以下是两者的主要日期类型对比&#xff1a;Oracle 日期类型DATE存储日期和时间&#xff08;精确到秒&#xff09;格式&#xff1a;YYYY-MM-DD HH24:MI:SS示例&#xff1a;TO_DATE(…

基于 Redis 实现共享 Session 登录的多种方法与实践

全文目录&#xff1a;开篇语**前言****1. 什么是共享 Session 登录&#xff1f;****2. 基于 Redis 实现共享 Session 的基本方法****2.1 通过 Redis 存储 Session 数据****2.1.1 基本流程****2.1.2 示例代码&#xff08;Java Spring Boot Redis&#xff09;****3. 使用 Redis…

spring cloud + easyRules 零基础搭建智能规则引擎

你是否曾想过在项目中嵌入一套轻量级且高度可扩展的规则引擎&#xff0c;轻松实现动态化的业务决策&#xff1f;在金融、电商、政务等领域&#xff0c;风险控制是业务安全的核心。传统硬编码方式很难应对复杂多变的风控需求&#xff0c;而规则引擎允许我们将这些规则独立出来&a…

AI应用:电路板设计

Diode Computers 公司 Diode Computers是一家专注于利用AI技术进行定制电路板设计和制造的公司&#xff0c;提供从概念到量产的全流程服务。其核心优势在于将电路板设计转化为AI可理解的代码形式&#xff0c;大幅提升设计效率并降低传统EDA工具的使用门槛 0。 核心服务 设计与制…

RocketMQ学习系列之——客户端消息确认机制

一、客户端使用MQ基本代码示例1、添加maven依赖<dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-client</artifactId><version>5.3.0</version> </dependency>2、生产者代码示例public class Produc…

[leetcode] 组合总和

39. 组合总和 - 力扣&#xff08;LeetCode&#xff09; i class Solution {int aim;vector<vector<int>> ret;vector<int> path; public:vector<vector<int>> combinationSum(vector<int>& nums, int target) {aim target;dfs(nums…

新能源行业B端极简设计:碳中和目标下的交互轻量化实践

新能源行业B端极简设计&#xff1a;碳中和目标下的交互轻量化实践内容摘要在新能源行业&#xff0c;碳中和目标正推动着企业追求更高的运营效率和更低的资源消耗。然而&#xff0c;传统的B端交互设计往往复杂繁琐&#xff0c;不仅增加了用户的操作成本&#xff0c;还可能导致资…

减速机:自动化生产线的“精密传动心脏”

减速机作为自动化生产线的核心传动部件&#xff0c;通过调节转速与扭矩实现设备精准控制&#xff0c;其在自动化生产线中发挥着关键作用。以下是其具体应用方式&#xff1a;输送线驱动在自动化生产线中&#xff0c;输送线用于运输物料、半成品或成品&#xff0c;通过减速机可以…

从0到1学PHP(五):PHP 数组:高效存储与处理数据

目录一、数组的定义与分类1.1 索引数组1.2 关联数组1.3 多维数组二、数组的基本操作2.1 数组元素的添加、删除、修改和访问2.2 数组指针的操作三、数组处理函数3.1 数组排序函数3.2 数组统计函数3.3 数组过滤与转换函数一、数组的定义与分类 在 PHP 中&#xff0c;数组是一种非…

vscode 字体的跟换

打开vscode 左下角输入电脑中已经有的字体&#xff1a;有想要用的可以自己进行安装刷新这样就可改变了

墨者:SQL过滤字符后手工注入漏洞测试(第3题)

1. 墨者学院&#xff1a;SQL过滤字符后手工注入漏洞测试(第3题)&#x1f680; 因为练习过太多的sql注入&#xff0c;废话不多介绍&#xff0c;我会通过围绕手动注入和工具爆破的方式达到靶场目标&#xff0c;开练&#xff01;&#xff01;&#xff01; 2. 手工注入方式&#x1…

【Spring AI实战】实现仿DeepSeek页面对话机器人(支持多模态上传)

一、前言 二、实现效果 三、代码实现 3.1 后端代码 3.2 前端代码 一、前言 Spring AI详解&#xff1a;【Spring AI详解】开启Java生态的智能应用开发新时代(附不同功能的Spring AI实战项目)-CSDN博客 二、实现效果 可上传图片或音频数据给大模型分析 三、代码实现 3.1 后…

Vue 正在热映模块

Vue 渐进式JavaScript 框架 基于Vue2的移动端项目&#xff1a;正在热映模块 目录 正在热映 数据修改 导入axios 配置反向代理 正在热映渲染 赋值数据 渲染列表 显示图片 优化列表 设置列表样式 主演 定义过滤器 使用过滤器 主演过长处理 无主演情况处理 观众评…

阿里云上进行k8s集群的配置

在阿里云容器服务Kubernetes&#xff08;ACK&#xff09;中配置集群的核心步骤可分为以下六大关键环节&#xff0c;涵盖架构设计到运维管理&#xff1a;1. 集群规划与基础配置 集群类型选择 托管版&#xff1a;Master节点由阿里云托管&#xff08;推荐生产环境&#xff09;专有…

页面性能优化

优化点解决方案效果双向绑定数量过多竞对设置单元格内部涉及双向绑定的输入组件过多&#xff0c;线上页面最多有88个该和抽屉中的编辑表格一样的组件&#xff0c;共计930个&#xff08;按每行最少6个来计算的&#xff09;双向绑定的组件&#xff0c;严重拖累页面性能。数据计算…

详细说明零拷贝

详细说明零拷贝【一】零拷贝介绍【1】说明【2】为什么需要零拷贝&#xff1f;—— 传统数据传输的问题【3】零拷贝的核心优化【4】零拷贝的实现方式&#xff08;1&#xff09;mmap&#xff08;内存映射&#xff09;&#xff08;2&#xff09;sendfile&#xff08;Linux 系统调用…