返回顶部
首页 > 资讯 > 前端开发 > VUE >Config中怎么实现配置热刷新
  • 301
分享到

Config中怎么实现配置热刷新

2024-04-02 19:04:59 301人浏览 独家记忆
摘要

Config中怎么实现配置热刷新,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。问题1. 如何实现配置热刷新重点 Nacos原理:1.在需要

Config中怎么实现配置热刷新,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

问题1. 如何实现配置热刷新重点 Nacos原理:

  • 1.在需要热刷新的Bean上使用spring cloud原生注解 @RefreshScope

  • 2.当有配置更新的时候调用contextRefresher.refresh()

代码如下:

@RestController @RequestMapping("/config") @RefreshScope // 重点 public class ConfiGController {     @Value("${laker.name}") // 待刷新的属性     private String lakerName;     @RequestMapping("/get")     public String get() {         return lakerName;     }  ... }

1. @RefreshScope原理

@RefreshScope位于spring-cloud-context,源码注释如下:

可将@Bean定义放入org.springframework.cloud.context.scope.refresh.RefreshScope中。用这种方式注解的Bean可以在运行时刷新,并且使用它们的任何组件都将在下一个方法调用前获得一个新实例,该实例将完全初始化并注入所有依赖项。

要清楚RefreshScope,先要了解Scope

Scope(org.springframework.beans.factory.config.Scope)是Spring  2.0开始就有的核心的概念

RefreshScope(org.springframework.cloud.context.scope.refresh),  即@Scope("refresh")是spring cloud提供的一种特殊的scope实现,用来实现配置、实例热加载。

类似的有:

  • RequestScope:是从当前WEB request中获取实例的实例

  • SessionScope:是从Session中获取实例的实例

  • ThreadScope:是从ThreadLocal中获取的实例

RefreshScope是从内建缓存中获取的。

2. ContextRefresher.refresh()

当有配置更新的时候,触发ContextRefresher.refresh

RefreshScope 刷新过程

入口在ContextRefresher.refresh

public synchronized Set<String> refresh() { ①  Map<String, Object> before = extract(this.context.getEnvironment().getPropertySources()); ②  updateEnvironment(); ④  Set<String> keys = changes(before, ③extract(this.context.getEnvironment().getPropertySources())).keySet(); ⑤  this.context.publishEvent(new EnvironmentChangeEvent(this.context, keys)); ⑥       this.scope.refreshAll(); }

①提取标准参数(SYSTEM,JNDI,SERVLET)之外所有参数变量

②把原来的Environment里的参数放到一个新建的Spring  Context容器下重新加载,完事之后关闭新容器(重点:可以去debug跟踪下,实际上是重启了个SpringApplication)

③提起更新过的参数(排除标准参数)

④比较出变更项

⑤发布环境变更事件

⑥RefreshScope用新的环境参数重新生成Bean,重新生成的过程很简单,清除refreshscope缓存幷销毁Bean,下次就会重新从BeanFactory获取一个新的实例(该实例使用新的配置)

3. RefreshScope.refreshAll()

RefreshScope.refreshAll方法实现,即上面的第⑥步调用:

public void refreshAll() {   super.destroy();   this.context.publishEvent(new RefreshScopeRefreshedEvent()); }

RefreshScope类中有一个成员变量 cache,用于缓存所有已经生成的 Bean,在调用 get  方法时尝试从缓存加载,如果没有的话就生成一个新对象放入缓存,并通过 getBean 初始化其对应的 Bean:

public Object get(String name, ObjectFactory<?> objectFactory) {  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;  } }

所以在销毁时只需要将整个缓存清空,下次获取对象时自然就可以重新生成新的对象,也就自然绑定了新的属性:

public 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(); }

清空缓存后,下次访问对象时就会重新创建新的对象并放入缓存了。

而在清空缓存后,它还会发出一个 RefreshScopeRefreshedEvent 事件,在某些 Spring Cloud  的组件中会监听这个事件并作出一些反馈。

4. 模拟造轮子

这里我们就可以模拟造个热更新的轮子了;

代码以及配置如下:

  • 项目依赖spring-cloud-context

<dependency>   <groupId>org.springframework.cloud</groupId>   <artifactId>spring-cloud-context</artifactId> </dependency>
  • 配置bean

@Component @RefreshScope public class User {     @Value("${laker.name}")     private String name;     ... }
  • 刷新接口以及查看接口

@RestController @RequestMapping("/config") public class ConfigController {     @Autowired     User user;     @Autowired     ContextRefresher contextRefresher;     @RequestMapping("/get")     public String get() {         return user.getName();     }     @RequestMapping("/refresh")     public String[] refresh() {         Set<String> keys = contextRefresher.refresh();         return keys.toArray(new String[keys.size()]);     }
  • application.yml

laker:   name: laker

操作流程如下:

1.浏览器Http://localhost:8080/config/get - 浏览器结果:laker

2.修改application.yml里面内容为:

laker:   name: lakerupdate

3.浏览器http://localhost:8080/config/refresh - 浏览器结果:laker.name

4.浏览器http://localhost:8080/config/get - 浏览器结果:lakerupdate(未重新启动,实现了配置更新)

问题2.  Nacos客户端如何实时监听到Nacos服务端配置更新了

这里可以去看下Nacos源码,使用的是长轮询,什么是长轮询以及其其他替代协议?

自己花了几个小时去看Nacos长轮询源码,太多了不太好理解,有兴趣的自行Google。一般我们都是基于Spring  Boot的后台了,各种google后,发现Apollo实现较为简单,所以直接拿Apollo的代码借鉴。

1. Apollo 实现方式

实现方式如下:

  1. 鸿蒙官方战略合作共建——HarmonyOS技术社区

  2. 客户端会发起一个Http请求到Config  Service的notifications/v2接口,也就是NotificationControllerV2,参见RemoteConfigLongPollService

  3. NotificationControllerV2不会立即返回结果,而是通过Spring DeferredResult把请求挂起

  4. 如果在60秒内没有该客户端关心的配置发布,那么会返回Http状态码304给客户端

  5. 如果有该客户端关心的配置发布,NotificationControllerV2会调用DeferredResult的setResult方法,传入有配置变化的namespace信息,同时该请求会立即返回。客户端从返回的结果中获取到配置变化的namespace后,会立即请求Config  Service获取该namespace的最新配置。

解读下:

  • 关键词DeferredResult,使用这个特性来实现长轮询

  • 超时返回的时候,是返回的状态码Http Code 304

释义:自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容,进而节省带宽和开销。

2. 什么是DeferredResult

异步支持是在Servlet 3.0中引入的,简单来说,它允许在请求接收器线程之外的另一个线程中处理HTTP请求。

从Spring 3.2开始可用的DeferredResult有助于将长时间运行的计算从http-worker线程卸载到单独的线程。

尽管另一个线程将占用一些资源来进行计算,但不会阻止工作线程,并且可以处理传入的客户端请求。

异步请求处理模型非常有用,因为它有助于在高负载期间很好地扩展应用程序,尤其是对于IO密集型操作。

DeferredResult是对异步Servlet的封装

具体可以参考我在CSDN写的Spring Boot 使用DeferredResult实现长轮询

这里借助互联网上的一个图就更清晰些。

Servlet异步流程图

Config中怎么实现配置热刷新

接收到request请求之后,由Tomcat工作线程从httpservletRequest中获得一个异步上下文AsyncContext对象,然后由tomcat工作线程把AsyncContext对象传递给业务处理线程,同时tomcat工作线程归还到工作线程池,这一步就是异步开始。在业务处理线程中完成业务逻辑的处理,生成response返回给客户端。

3. 模拟造轮子

这里我们通过使用 Spring Boot 来简单的模拟一下如何通过 Spring Boot DeferredResult 来实现长轮询服务推送的。

代码如下,仅供参考:

 @RestController @RequestMapping("/config") public class LakerConfigController {     private final Logger logger = LoggerFactory.getLogger(this.getClass());     //guava中的Multimap,多值map,对map的增强,一个key可以保持多个value     private Multimap<String, DeferredResult<String>> watchRequests = Multimaps.synchronizedSetMultimap(HashMultimap.create());          @RequestMapping(value = "/get/{dataid}")     public DeferredResult<String> watch(@PathVariable("dataId") String dataId) {         logger.info("Request received");         ResponseEntity<String>                 NOT_MODIFIED_RESPONSE = new ResponseEntity<>(HttpStatus.NOT_MODIFIED);         // 超时时间30s 返回 304 状态码告诉客户端当前命名空间的配置文件并没有更新         DeferredResult<String> deferredResult = new DeferredResult<>(30 * 1000L, NOT_MODIFIED_RESPONSE);         //当deferredResult完成时(不论是超时还是异常还是正常完成),移除watchRequests中相应的watch key         deferredResult.onCompletion(() -> {             logger.info("remove key:" + dataId);             watchRequests.remove(dataId, deferredResult);         });         deferredResult.onTimeout(() -> {             logger.info("onTimeout()");         });         watchRequests.put(dataId, deferredResult);         logger.info("Servlet thread released");         return deferredResult;     }          @RequestMapping(value = "/update/{dataId}")     public Object publishConfig(@PathVariable("dataId") String dataId) {         if (watchRequests.containsKey(dataId)) {             Collection<DeferredResult<String>> deferredResults = watchRequests.get(dataId);             Long time = System.currentTimeMillis();             //通知所有watch这个namespace变更的长轮训配置变更结果             for (DeferredResult<String> deferredResult : deferredResults) {                 //deferredResult一旦执行了setResult()方法,就说明DeferredResult正常完成了,会立即把结果返回给客户端                 deferredResult.setResult(dataId + " changed:" + time);             }         }         return "success";     } }

操作流程如下:

为了简便我用浏览器模拟,实际用Java Http Client,例如:okhttp、Apache http client等

正常流程:

  • client1浏览器http://localhost:8080/config/get/laker,阻塞中ing

  • client2浏览器http://localhost:8080/config/update/laker,返回success

  • client1浏览器http://localhost:8080/config/get/laker,返回laker  changed:1611022736865

超时流程:

  • client1浏览器http://localhost:8080/config/get/laker,阻塞中ing

  • 30s后

  • client1浏览器,返回http code 304

Config中怎么实现配置热刷新

关于Config中怎么实现配置热刷新问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注编程网VUE频道了解更多相关知识。

--结束END--

本文标题: Config中怎么实现配置热刷新

本文链接: https://lsjlt.com/news/68132.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Config中怎么实现配置热刷新
    Config中怎么实现配置热刷新,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。问题1. 如何实现配置热刷新重点 Nacos原理:1.在需要...
    99+
    2024-04-02
  • springboot自动刷新配置怎么实现
    在Spring Boot中,可以通过使用Spring Cloud Config或Spring Boot Actuator来实现自动刷...
    99+
    2023-10-10
    springboot
  • spring cloud config和bus组件怎么实现自动刷新功能
    本篇内容主要讲解“spring cloud config和bus组件怎么实现自动刷新功能”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“spring cloud config和bus组件怎么实现自...
    99+
    2023-06-25
  • webpack中怎么配置服务热更新
    这篇文章主要讲解了“webpack中怎么配置服务热更新”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“webpack中怎么配置服务热更新”吧!   热更新的...
    99+
    2024-04-02
  • linux怎么刷新配置文件
    在Linux中,要刷新配置文件,可以通过以下几种方式: 重新启动服务:如果修改的是某个服务的配置文件,可以通过重新启动该服务来刷新...
    99+
    2024-02-29
    linux
  • apollo怎么更改配置刷新@ConfigurationProperties配置类
    这篇文章主要介绍了apollo怎么更改配置刷新@ConfigurationProperties配置类的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇apollo怎么更改配置刷新@ConfigurationProp...
    99+
    2023-07-05
  • spring cloud config和bus组件实现自动刷新功能
    1.启动RabbitMQ 2.修改config服务端 依赖:(boot和cloud版本不要太高,不然刷新配置的请求不能用) <dependencies> &l...
    99+
    2024-04-02
  • webpack如何实现热加载自动刷新
    这篇文章主要介绍webpack如何实现热加载自动刷新,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!具体如下:一、webpack-dev-server 一个轻量级的服务 功能:修改代码...
    99+
    2024-04-02
  • ssh之 ~/.ssh/config 配置文件实现
    文章目录 ~/.ssh/config配置实现常用的SSH配置项测试 ~/.ssh/config配置实现 参考 最常用的登陆方法是**ssh username@server -p por...
    99+
    2023-09-08
    ssh 服务器 运维
  • ListView中怎么实现部分刷新
    在ListView中实现部分刷新可以通过调用Adapter的notifyItemChanged()方法来实现。 首先,在你的Ad...
    99+
    2023-10-26
    ListView
  • MongoDB中怎么修复config配置节点
    这期内容当中小编将会给大家带来有关MongoDB中怎么修复config配置节点,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。修复流程如下:# 登录到config库,查看c...
    99+
    2024-04-02
  • react 怎么实现热更新
    本教程操作环境:Windows10系统、react18版、Dell G3电脑。react 怎么实现热更新?[React] create-react-app 实现热更新一、使用以下命令行下载 react-hot-loaderyarn add ...
    99+
    2023-05-14
    React
  • nacos怎么实现热更新
    要实现 Nacos 的热更新,可以按照以下步骤操作:1. 在 Nacos 控制台上创建一个配置。2. 在应用程序中引入 Nacos ...
    99+
    2023-08-26
    nacos
  • docker热更新怎么实现
    Docker 热更新可以通过以下几种方式来实现: 使用 Docker Compose:可以使用 Docker Compose 来...
    99+
    2023-10-27
    docker
  • ASP.NET中怎么实现无刷新分页
    本篇文章给大家分享的是有关ASP.NET中怎么实现无刷新分页,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。新建一个分页存储过程:CREATE procedure&nb...
    99+
    2023-06-17
  • android中recyclerview局部刷新怎么实现
    在Android中,通过RecyclerView的notifyItemChanged()方法可以实现局部刷新。该方法用于更新指定位置...
    99+
    2024-03-08
    android
  • java怎么读取config中的配置文件
    在Java中,可以使用Properties类来读取配置文件。下面是一个简单的示例: import java.io.FileInput...
    99+
    2024-02-29
    java
  • Spring boot 应用实现动态刷新配置详解
    目录1. 依赖2. 配置暴露接口3. @RefreshScope4. 启动服务6. 获取配置值7. 刷新配置 重新获取总结前面写过一篇《Spring Cloud Bus 实现配置实时...
    99+
    2024-04-02
  • 怎么实现代码热更新
    本篇内容主要讲解“怎么实现代码热更新”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么实现代码热更新”吧!猴子补丁猴子补丁 ( monkey patch )大家...
    99+
    2024-04-02
  • 怎么用import.meta实现热更新
    这篇“怎么用import.meta实现热更新”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么用import.meta实现热...
    99+
    2023-06-30
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作