@RefreshScope热更新原理

简介: @RefreshScope通过组合注解实现配置热更新,核心在于@Scope("refresh")。其原理是将Bean加入自定义缓存,配置变更时清空缓存并触发Spring重新创建Bean实例,结合Environment更新,使@Value等属性动态刷新,实现毫秒级配置热加载,本质是缓存失效+Bean重建机制。

@RefreshScope热更新原理
在前面学习Nacos的章节中,为了实现配置的热更新我们采取了两种方式,其一就是借助于注解:@RefreshScope,那么这个注解是如何做到标识即生效的?我们尝试一起分析一下。
1.了解@RefreshScope本身
点击进去此注解,可以发现其本质也是一个组合注解,如下
对于Spring注解有过研究的读者,对于这几个元注解一定不陌生,简短的篇幅了解一下:
@Target({ ElementType.TYPE, ElementType.METHOD })
目标的作用范围
ElementType.TYPE:能修饰类、接口或枚举类型
ElementType.FIELD:能修饰成员变量
ElementType.METHOD:能修饰方法
ElementType.PARAMETER:能修饰参数
ElementType.CONSTRUCTOR:能修饰构造器
ElementType.LOCAL_VARIABLE:能修饰局部变量
ElementType.ANNOTATION_TYPE:能修饰注解
ElementType.PACKAGE:能修饰包
@Retention(RetentionPolicy.RUNTIME)
保留的生命周期
SOURCE:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;即保留在.java文件中
CLASS:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期;即保留在.class文件中
RUNTIME:注解不仅被保存到class文件中,jvm加载class文件之后仍然存在;即保留在内存中的字节码文件中,一旦jvm加载就会更新,生命周期最长
@Scope("refresh")
实现配置、实例热加载的关键核心,默认了ScopedProxyMode.TARGET_CLASS; 属性,此属性的功能就是在创建一个代理,在每次调用的时候都用它来调用GenericScope get 方法来获取对象。集成了Spring框架之后,实际就是调用Spring的装配机制重新装配属性。
所以截止目前我们可以了解到:@RefreshScope注解本身是一个组合注解,其实现配置热更新的关键是依赖@Scope("refresh")。我们进一步来看看@RefreshScope到底做了什么?
2.@RefreshScope做了什么
@RefreshScope主要就是基于@Scope注解的作用域代理的基础上进行扩展实现的,加了@RefreshScope注解的类,在被Bean工厂创建后会加入自己的refresh scope 这个Bean缓存中,后续会优先从Bean缓存中获取,当配置中心发生了变更,会把变更的配置更新到spring容器的Environment中,并且同时bean缓存就会被清空,从而就会从bean工厂中创建bean实例了,而这次创建bean实例的时候就会继续经历这个bean的生命周期,使得@Value属性值能够从Environment中获取到最新的属性值,这样整个过程就达到了动态刷新配置的效果。
所以截止目前我们可以了解到下述大致流程:
Spring获取标注@RefreshScope的Bean流程
配置更新清空缓存​
开始
获取标注@Scope的Bean

refresh scope缓存是否有

调用Spring创建过程全新创建

返回并结束

refresh scope缓存bean

Nacos配置更新
清空​
加入新创建bean​
清空的目的是为了重新创建,获取全新的Bean从而达到动态更新,这个过程非常快(ms级)

3.@RefreshScope怎么做到的
基于上面我们知道,@Scope基于缓存失效,实现配置的热更新,我们继续看看它是如何做到的:
4.总结
对于@RefreshScope注解实现配置热更新的流程,实际是借助于缓存失效+Spring重新创建配置Bean解决,知道这个思路之后,读者们可以借助本章节2,或3做流程性、原理性了解。

相关文章
|
NoSQL Redis
M1 MacBook安装redis
M1 MacBook安装redis
1031 0
|
Dubbo Java 应用服务中间件
项目中引进这玩意,排查日志又快又准
随着微服务盛行,很多公司都把系统按照业务边界拆成了很多微服务,在排错查日志的时候,因为业务链路贯穿着很多微服务节点,导致定位某个请求的日志以及上下游业务的日志会变得有些困难。
|
9月前
|
消息中间件 人工智能 监控
文生图架构设计原来如此简单之分布式服务
想象一下,当成千上万的用户同时要求AI画图,如何公平高效地处理这些请求?文生图/图生图大模型的架构设计看似复杂,实则遵循简单而有效的原则:合理排队、分工明确、防患未然。
352 14
文生图架构设计原来如此简单之分布式服务
|
SQL JSON 缓存
你了解 SpringBoot 在一次 http 请求中耗费了多少内存吗?
在工作中常需进行全链路压测并优化JVM参数。通过实验可精确计算特定并发下所需的堆内存,并结合JVM新生代大小估算GC频率,进而优化系统。实验基于SpringBoot应用,利用JMeter模拟并发请求,分析GC日志得出:单次HTTP请求平均消耗约34KB堆内存。复杂环境下,如公司线上环境,单次RPC请求内存消耗可达0.5MB至1MB,揭示了高并发场景下的内存管理挑战。
|
存储 缓存 负载均衡
OpenFeign高级用法:缓存、QueryMap、MatrixVariable、CollectionFormat优雅地远程调用
OpenFeign高级用法:缓存、QueryMap、MatrixVariable、CollectionFormat优雅地远程调用
|
缓存 Java 编译器
JRE、JDK、JVM 和 JIT 之间的区别详解
【8月更文挑战第22天】
755 0
|
存储 SQL 前端开发
解决深度分页问题
解决深度分页问题
form-data 与 x-www-form-urlencode有何区别?
在客户端和服务器之间传递数据既可以使用`form-data` ,又可以使用 `x-www-form-urlencoded` 。但是在使用时你有注意它们的区别吗?
578 2
|
Java Spring
Spring Event陷阱重重,我为何含泪放弃?
网络上比较推崇使用Spring Event 优雅的实现观察者模式。我在调研后也确实觉得这种方式能实现业务逻辑上的解耦,但线上的一次事故,让我意识到 Spring Event远远没有那么简单。
898 1
Spring Event陷阱重重,我为何含泪放弃?
|
存储 缓存 搜索推荐
复杂系统设计原则与案例
## 一、复杂是软件的本质属性 ### 1.1 复杂是软件的本质属性 正如Brooks所言,软件复杂性是软件固有的属性,这种固有的复杂性主要由4个方面的原因造成的: - 问题域的复杂性 - 管理开发过程的复杂性 - 随处可变的灵活性 - 描绘离散系统行为的问题 上面每一个方面都有极大的挑战,以「问题域的复杂性」为例,现在我们的大型系统中,动不动就几十个应用,组合在一起就是一个复杂的系统,而每个
1693 4
复杂系统设计原则与案例