Springcloud中的@RefreshScope详解

一、概述
@RefreshScope注解是Spring Cloud中的一个注解,它用来实现Bean中属性的动态刷新,这意味着您可以在不停止和重新启动应用程序的情况下更改配置,它在微服务配置中心的场景下经常出现。

二、@RefreshScope 实现动态刷新的原理
1.在应用程序中使用 @RefreshScope 注解时,这个注解内部使用了@Scope注解,并将其值设置为"refresh",定义了一个新的作用域名为refresh。

2.当Spring容器启动时,它会解析所有的Bean定义,并遇到@RefreshScope注解时,Spring容器会知道这是一个特殊的作用域。它使用RefreshScope类(继承自GenericScope)来处理这些Bean的生命周期

3.当应用首次请求一个被@RefreshScope标记的Bean时,Spring容器会调用RefreshScope的get方法来创建Bean的实例,创建完成后,这个Bean实例会被缓存在RefreshScope中,以便后续快速获取。

4.在应用运行时,如果外部配置源中的配置发生了更改(比如通过 Nacos Server),客户端应用需要被通知到这些更改。

5.客户端应用可以通过多种方式触发刷新事件,比如通过Spring Cloud Bus广播配置更改消息。

6.在刷新事件被触发之前或之后,需要更新本地的Environment对象,以反映外部配置源中的最新配置。

7.当Environment对象更新后,RefreshScope会遍历其缓存中的所有Bean,对它们进行销毁和重新创建。这是通过调用GenericScope提供的生命周期管理方法来完成的。旧的Bean实例被销毁,新的Bean实例根据最新的配置(从更新后的Environment中获取)被创建并缓存。

8.经过刷新操作后,应用中的Bean将使用新的配置。由于@RefreshScope仅影响标记了此注解的Bean,因此未标记的Bean不会受到影响。

三、如何在 Spring Boot中使用 @RefreshScope?
1.添加 相关的Maven 依赖

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId>
</dependency>

2.创建一个需要刷新的bean对象。

@Component
@RefreshScope
public class RefleshBean {@Value("${config.property}")private String configProperty;public String getConfigProperty() {return configProperty;}
}

上面我们使用 @RefreshScope 注解标记 RefleshBean 类。这意味着当 config.property属性更改时,Spring Boot 将重新加载这个 bean。

四、@RefreshScope 源码解析
1.首先看下@RefreshScope 注解

package org.springframework.cloud.context.config.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;/*** Convenience annotation to put a <code>@Bean</code> definition in* {@link org.springframework.cloud.context.scope.refresh.RefreshScope refresh scope}.* Beans annotated this way can be refreshed at runtime and any components that are using* them will get a new instance on the next method call, fully initialized and injected* with all dependencies.** @author Dave Syer**/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {/*** @see Scope#proxyMode()* @return proxy mode*/ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;}

可以看出其是一个复合注解,被标注了 @Scope(“refresh”),@RefreshScope 是scopeName="refresh"的 @Scope。

2.RefreshScope的实现
2.1 RefreshScope 继承GenericScope,其父类GenericScope的get方法实现获取Bean,注意创建Bean还是由IOC#createBean实现。
GenericScope类

    @Overridepublic Object get(String name, ObjectFactory<?> objectFactory) {//通过cache把bean缓存下来,如果不存在则创建BeanLifecycleWrapper value = this.cache.put(name, new BeanLifecycleWrapper(name, objectFactory));this.locks.putIfAbsent(name, new ReentrantReadWriteLock());try {return value.getBean();}catch (RuntimeException e) {this.errors.put(name, e);throw e;}}

GenericScope 里面的 get 方法负责对象的创建和缓存。

上面代码中看似每次都新创建一个对象放入缓存中,实际上是创建了一个objectFactory的封装对象,并没有真正创建对象。而cache的put逻辑最终实现为map的putIfAbsent,即缓存中已存在key则返回原来的value。实现在 StandardScopeCache类

public class StandardScopeCache implements ScopeCache {private final ConcurrentMap<String, Object> cache = new ConcurrentHashMap<String, Object>();	// ...public Object put(String name, Object value) {Object result = this.cache.putIfAbsent(name, value);if (result != null) {return result;}return value;}
}

2.2 RefreshScope缓存清理。
配置更新后需要清除RefreshScope中的缓存,ContextRefresher负责完成这一任务。它由RefreshAutoConfiguration引入,创建的时候会自动注入RefreshScope和context。

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RefreshScope.class)
@ConditionalOnProperty(name = RefreshAutoConfiguration.REFRESH_SCOPE_ENABLED,matchIfMissing = true)
@AutoConfigureBefore(HibernateJpaAutoConfiguration.class)
public class RefreshAutoConfiguration {	@Bean@ConditionalOnMissingBean(RefreshScope.class)public static RefreshScope refreshScope() {return new RefreshScope();}@Bean@ConditionalOnMissingBeanpublic ContextRefresher contextRefresher(ConfigurableApplicationContext context,RefreshScope scope) {return new ContextRefresher(context, scope);}// ...
}

2.3 ContextRefresher的refresh方法就是清理RefreshScope缓存的入口。

public synchronized Set<String> refresh() {Set<String> keys = refreshEnvironment();this.scope.refreshAll();return keys;
}

其中refreshAll最终会落实到GenericScope的destroy方法,其中清理了所有的缓存。

	@Overridepublic void destroy() {List<Throwable> errors = new ArrayList<Throwable>();Collection<BeanLifecycleWrapper> wrappers = this.cache.clear();for (BeanLifecycleWrapper wrapper : wrappers) {try {Lock lock = this.locks.get(wrapper.getName()).writeLock();lock.lock();try {wrapper.destroy();}finally {lock.unlock();}}catch (RuntimeException e) {errors.add(e);}}if (!errors.isEmpty()) {throw wrapIfNecessary(errors.get(0));}this.errors.clear();}

2.4 重新加载
想实现动态刷新配置,光清除RefreshScope的缓存还不够,还要具备重新加载配置到context中的能力,这一任务也是ContextRefresher完成的。
实际上就是在refresh方法中清理RefreshScope缓存之前,即refreshEnvironment方法中完成了配置的重新加载。

public synchronized Set<String> refreshEnvironment() {Map<String, Object> before = extract(this.context.getEnvironment().getPropertySources());addConfigFilesToEnvironment();Set<String> keys = changes(before,extract(this.context.getEnvironment().getPropertySources())).keySet();this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys));return keys;
}

总结:
带有@RefreshScope注解的Bean在配置发生变化时进行刷新,可以确保配置的动态生效。但是,使用@RefreshScope并不是必须的。如果你希望配置的变化立即生效,并且不想手动刷新Bean,可以直接使用@ConfigurationProperties注解来获取配置项的值,这样配置的变化会立即反映在应用程序中。使用@RefreshScope的目的是延迟Bean的刷新,只在需要的时候才进行刷新。这对于一些开销较大的Bean或需要动态加载配置的场景比较合适。

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

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

相关文章

粮油包装生产线的未来趋势:智能、环保与可持续发展

在当今世界&#xff0c;科技进步日新月异&#xff0c;智能化、环保和可持续发展已成为各行各业关注的焦点。粮油包装生产线作为食品产业链的重要环节&#xff0c;其未来发展趋势同样离不开这三大主题。星派将探讨粮油包装生产线的未来趋势&#xff0c;并展望其在智能、环保与可…

详解俄罗斯社媒平台VK广告推广如何开户?VK代理开户、费用、代运营流程

俄罗斯的VK&#xff08;VKontakte&#xff09;是当地常用的社交媒体平台&#xff0c;对于想要在俄罗斯市场推广产品的企业来说&#xff0c;VK广告投放是一个有效的渠道。以下是关于如何在VK上进行广告推广的开户流程、费用和代运营流程的详解&#xff1a; VK广告推广开户流程 …

海康Visionmaster-常见问题排查方法-启动阶段

VM试用版启动时&#xff0c;弹窗报错&#xff1a;加密狗未安装或检测异常&#xff1b;  问题原因&#xff1a;安装VM 的时候未选择软加密&#xff0c;选择了加密狗驱动&#xff0c;此时要使用软授权就出现了此现象。  解决方法&#xff1a; ① 首先确认软加密驱动正确安装…

机器学习入门:玩转sklearn库,AI写作

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

达芬奇调色:色彩理论入门

写在前面 整理一些达芬奇调色的笔记博文内容涉及&#xff1a; 一级调色是什么&#xff0c;以及 调色素材格式 log&#xff0c;raw&#xff0c;rec709 简单认知理解不足小伙伴帮忙指正 不必太纠结于当下&#xff0c;也不必太忧虑未来&#xff0c;当你经历过一些事情的时候&#…

基于SpringBoot+Vue的企业资产管理系统设计与实现

1、系统演示视频&#xff08;演示视频&#xff09; 2、需要请联系

hexo配置教程、主题使用及涉及的技术学习

一、背景 最近,一直想做一个属于自己的网站.可以从零开始搭建一个网站,顺便可以把日常中学到的技术用于实战,还可以顺便记录自己的所思所感,记录成长的过程. 方案 一开始的方案是从零开始,模仿常见个人博客的设计,基于vueSpringbootMySQL的去实现网站. 新建项目之后,发现vu…

C/C++ 入门(7)string类(STL)

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;C 请多多指教&#xff01; 目录 一、标准库中的string 1、了解 2、string类常用接口说明 1、常见的构造函数 2、容量操作 ​编辑 3、访问及遍历操作 4、修改操作 5、非成员函数 二、string类实现 …

如何训练一个大语言模型(LLMs)

目录 前言大语言模型 Vs机器学习模型训练过程步骤1&#xff1a;数据策划&#xff08;Data Curation)步骤2&#xff1a;格式化与预处理步骤3&#xff1a;训练模型步骤4&#xff1a;模型评估 LLM Leaderboard[LLM Leaderboard 2024](https://www.vellum.ai/llm-leaderboard)[Open…

软考 系统架构设计师系列知识点之大数据设计理论与实践(13)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之大数据设计理论与实践&#xff08;12&#xff09; 所属章节&#xff1a; 第19章. 大数据架构设计理论与实践 第4节 Kappa架构 19.4.2 Kappa架构介绍 Kappa架构由Jay Kreps提出&#xff08;Lambda由Storm之父Nayhan M…

智慧水务是什么样的?如何打造智慧水务大屏?

在信息化和数字化快速发展的今天&#xff0c;智慧水务作为城市供水管理的重要组成部分&#xff0c;正变得越来越重要。智慧水务大屏作为智慧水务系统的可视化核心&#xff0c;不仅提升了水务管理的效率&#xff0c;而且通过数据的实时监控和分析&#xff0c;为决策者提供了强有…

持续发力新能源新材料产业,企企通 ×『瑞翔新材』SRM项目启动,积极推动企业发展新质生产力

近日&#xff0c;南通瑞翔新材料有限公司&#xff08;以下简称“瑞翔新材”&#xff09;与企企通达成战略合作&#xff0c;并成功召开SRM项目启动会&#xff0c;瑞翔新材与企企通高层领导、项目负责人及项目组成员共同出席此次启动会。 本次项目建设&#xff0c;企企通将助力瑞…

微服架构基础设施环境平台搭建 -(六)Kubesphere 部署Redis服务 设置访问Redis密码

微服架构基础设施环境平台搭建 -&#xff08;六&#xff09;Kubesphere 部署Redis服务 & 设置访问Redis密码 微服架构基础设施环境平台搭建 系列文章 微服架构基础设施环境平台搭建 -&#xff08;一&#xff09;基础环境准备 微服架构基础设施环境平台搭建 -&#xff08;二…

矿产资源管理系统:开启智慧矿业新篇章

项目背景 在全球经济发展的大背景下&#xff0c;矿产资源作为工业的“粮食”和“血液”&#xff0c;其合理开发与有效管理对于国家的经济发展、能源安全和工业稳定供应具有不可替代的作用。然而&#xff0c;随着资源的日益紧张和环境保护要求的提高&#xff0c;传统的矿产资源…

canvas 学习

最近的项目涉及到 canvas 相关的知识&#xff0c;就在网站上找资源先大概了解一下&#xff0c;然后再细细研究。 看到了一篇 “canvas详细教程” 的资源&#xff0c;感觉十分不错&#xff0c;就分享给大家&#xff1a; canvas详细教程! ( 近1万字吐血总结)这期是潘潘整理的万…

Recommended Azure Monitors

General This document describes the recommended Azure monitors which can be implemented in Azure cloud application subscriptions. SMT incident priority mapping The priority “Blocker” is mostly used by Developers to prioritize their tasks and its not a…

第二届阿里巴巴大数据智能云上编程大赛亚军比赛攻略_北方的郎队

关联比赛: 第二届阿里巴巴大数据智能云上编程大赛-智联招聘人岗智能匹配 查看更多内容&#xff0c;欢迎访问天池技术圈官方地址&#xff1a;第二届阿里巴巴大数据智能云上编程大赛亚军比赛攻略_北方的郎队_天池技术圈-阿里云天池

C#-使用Harmony库实现DLL文件反射调用

一. Harmony工作原理 利用C#运行时Runtime的反射机制,动态加载dll中的方法,字段,属性,实现对DLL方法的重写和代码注入。 二. Harmony下载及安装 1.下载Harmony_lib库lib.harmony.2.3.3.nupkg 霸王•吕布 / CSharpHarmonyLib GitCodehttps://gitcode.net/qq_35829452/csharph…

【黑马点评Redis——003优惠券秒杀】

1.优惠券秒杀 1.1 全局ID生成器 1.1.1 什么是全局ID生成器 全局ID生成器&#xff0c;是一种在分布式系统下用来生成全局唯一ID的工具。 需要满足以下特性&#xff1a; 唯一性高可用高性能递增性安全性 1.1.2 为什么需要全局ID生成器&#xff1f; 自增ID存在的问题&#…

字节跳动(社招)三面算法原题

TikTok 喘息 继上月通过强制剥离 TikTok 法案后&#xff0c;美国众议院在当地时间 20 日下午以 360 票赞成 58 票反对通过了新的法案&#xff1a;剥离 TikTok 的期限由生效后 165 天调整至 270 天之内&#xff0c;即今年 11 月的美国总统大选后。 之前我们讲过&#xff0c;TikT…