nacos配置实时刷新@RefreshScope注解和定时任务@Scheduled注解同时使用导致失效问题

@RefreshScope@Scheduled的组合使用有时会导致@Scheduled任务失效,主要是由于它们在Spring中的工作机制不同。

@RefreshScope的工作原理

@RefreshScope是Spring Cloud中的一个注解,它允许在应用运行时刷新bean的属性,而不需要重启应用程序。具体来说,当配置变化时,@RefreshScope会重新创建bean实例,以便使新的配置生效。它依赖于Spring Cloud Context的刷新机制。

工作流程:

  1. Spring容器启动时,@RefreshScope会为标注的bean创建一个代理对象。
  2. 当配置变化触发刷新事件时,Spring Cloud Context会销毁旧的bean实例,并创建一个新的实例。
  3. 代理对象会在下次调用该bean时,委托给新的bean实例。

@Scheduled的工作原理

@Scheduled是Spring中的调度注解,用于声明方法在指定的时间间隔或指定的时间点运行。它由Spring的Task Scheduler管理。

工作流程:

  1. Spring容器启动时,会扫描所有标注了@Scheduled的方法,并将这些方法注册到Task Scheduler中。
  2. Task Scheduler根据方法上的调度参数,定期调用这些方法。

两者结合导致问题的原因

当一个@Scheduled方法所在的bean被标注为@RefreshScope时,以下问题可能会导致调度任务失效:

  1. Bean实例重建@RefreshScope会在配置变化时重新创建bean实例。这意味着原有的@Scheduled任务绑定到了旧的bean实例上。新创建的bean实例没有重新注册到Task Scheduler,导致调度任务失效。
  2. 代理对象@RefreshScope创建的代理对象在重新创建bean实例后,会指向新的实例。然而,Task Scheduler并不会感知到这种变化,它依然尝试调用旧实例中的方法,导致任务失效。

详细源码分析

@RefreshScope源码分析

 下面看@ReFreshScope注解源码

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}

@RefreshScope的核心注解是@Scope("refresh"),它通过ContextRefresher来实现bean的刷新。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {/*** Alias for {@link #scopeName}.* @see #scopeName*/@AliasFor("scopeName")String value() default "";/*** Specifies the name of the scope to use for the annotated component/bean.* <p>Defaults to an empty string ({@code ""}) which implies* {@link ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.* @since 4.2* @see ConfigurableBeanFactory#SCOPE_PROTOTYPE* @see ConfigurableBeanFactory#SCOPE_SINGLETON* @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST* @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION* @see #value*/@AliasFor("value")String scopeName() default "";/*** Specifies whether a component should be configured as a scoped proxy* and if so, whether the proxy should be interface-based or subclass-based.* <p>Defaults to {@link ScopedProxyMode#DEFAULT}, which typically indicates* that no scoped proxy should be created unless a different default* has been configured at the component-scan instruction level.* <p>Analogous to {@code <aop:scoped-proxy/>} support in Spring XML.* @see ScopedProxyMode*/ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;}

通过代码我们可以看到proxyMode 这个属性,其实就是@RefreshScope 实现的本质了。

我们需要关心的就是ScopedProxyMode.TARGET_CLASS 这个属性,此属性的功能就是在创建一个代理,在每次调用的时候都用它来调用GenericScope get 方法来获取对象。GenericScope是SpringCloud对Scope的一个实现,Scope的源码如下,我们主要关注get方法

看一下get方法的具体实现:

	@Overridepublic 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;}}

GenericScope 实现了 Scope 最重要的 get(String name, ObjectFactory<?> objectFactory) 方法,在GenericScope 里面 包装了一个内部类 BeanLifecycleWrapperCache 来对加了 @RefreshScope 从而创建的对象进行缓存,使其在不刷新时获取的都是同一个对象。(这里你可以把 BeanLifecycleWrapperCache 想象成为一个大Map 缓存了所有@RefreshScope 标注的对象)

知道了对象是缓存的,所以在进行动态刷新的时候,只需要清除缓存,重新创建就好了。 

@Scheduled注解分析

@Scheduled的核心类是ScheduledAnnotationBeanPostProcessor,它在容器启动时扫描并注册调度任务。

解决方案

为了解决@RefreshScope导致的@Scheduled失效问题,可以采取以下几种策略:

  1. 手动重新注册任务:监听配置刷新事件,手动重新注册@Scheduled任务。
@Component
public class ScheduledTaskRegistrar implements ApplicationListener<EnvironmentChangeEvent> {//注释内容可以不使用,直接实现方法,内部为空即可//@Autowired//private ScheduledTaskRegistrar taskRegistrar;@Overridepublic void onApplicationEvent(EnvironmentChangeEvent event) {//taskRegistrar.destroy();//taskRegistrar.afterPropertiesSet();}
}

2. 避免组合使用:尽量避免在同一个bean上同时使用@RefreshScope@Scheduled。因为配置刷新后会卸载类,并重新实例化类(如果类中存在计数等情况需要注意)

3. 使用自定义调度机制:创建一个自定义调度器,在配置刷新时重新初始化调度任务。

@Configuration
public class CustomSchedulerConfig {@Bean@RefreshScopepublic CustomScheduler customScheduler() {return new CustomScheduler();}
}public class CustomScheduler {private ScheduledFuture<?> future;@Autowiredprivate TaskScheduler taskScheduler;@PostConstructpublic void start() {future = taskScheduler.scheduleAtFixedRate(this::task, 5000);}@PreDestroypublic void stop() {if (future != null) {future.cancel(true);}}public void task() {// Task logic here}
}

通过上述分析和解决方案,可以更清楚地理解@RefreshScope@Scheduled的工作机制,并有效避免调度任务失效的问题。

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

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

相关文章

美国空军发布类ChatGPT产品—NIPRGPT

6月11日&#xff0c;美国空军研究实验室&#xff08;AFRL&#xff09;官网消息&#xff0c;空军部已经发布了一款生成式AI产品NIPRGPT。 据悉&#xff0c;NIPRGPT是一款类ChatGPT产品&#xff0c;可生成文本、代码、摘要等内容&#xff0c;主要为为飞行员、文职人员和承包商提…

文件没有权限问题:cannot create /opt/apollo/neo/data/log/monitor.log: Permission denied

问题描述 执行 aem bootstrap start --plus 命令启动 Dreamview 提示错误&#xff1a; /bin/sh: 1: cannot create /opt/apollo/neo/data/log/monitor.log: Permission denied [ERROR] Failed to start Dreamview. Please check /opt/apollo/neo/data/log/dreamview.log or /op…

【React】在 React 组件中,怎么使用useContext

在React中,useContext 是一个Hook,它允许你无需显式地通过组件树的每一层来传递 props,就能将值深入到组件树的任何位置。要使用 useContext,你需要先创建一个 Context 对象,然后使用这个对象提供的 Provider 组件来包裹你的应用中的一部分。然后,任何在这个 Provider 下…

使用R语言生成CDISC SDTM.AE domain

写在前面 - 使用的是Rstudio - 其实R已经有生成sdtm相关的package&#xff0c;以下代码仅作为练习R语言的语法&#xff0c;不是高效生成sdtm的方法 - 代码中没有解决的问题包括&#xff1a;EPOCH相关的逻辑没有考虑partial date的情况&#xff1b;在使用arrange() function做…

ArrayList和LinkedList的区别!!!

总结&#xff1a; 1、数据结构的实现 ArrayList&#xff1a;动态数组。 LinkedList&#xff1a;双向链表。 2、时间复杂度不同 ArrayList&#xff1a;O(1) LinkedList: O(n) ①&#xff1a;随机访问---- ArrayList > LinkedList &#xff08;ArrayList采用下标&#xff0…

ARM-V9 RME(Realm Management Extension)系统架构之调试

安全之安全(security)博客目录导读 本节中&#xff0c;“RMSD外部调试”一词用于描述任何系统或PE的外部调试功能&#xff0c;这些功能能够实现以下目的&#xff1a; 监控或修改RMSD行为。对Realm PAS或Realm安全状态的外部访问。 本节中&#xff0c;“Root外部调试”一词用于…

C++ 实现HTTP的客户端、服务端demo和HTTP三方库介绍

本文使用C模拟实现http的客户端请求和http的服务端响应功能&#xff0c;并介绍几种封装HTTP协议的三方库。 1、实现简单HTTP的服务端功能 本程序使用C tcp服务端代码模拟HTTP的服务端&#xff0c;服务端返回给客户端的消息内容按照HTTP协议的消息响应格式进行了组装。 demo如…

PC端剪映6.0免vip版本,功能随便用

下载解压后点击“JianyingPro.exe”图标即可使用&#xff0c;使用过程中无需登陆账号。操作很简单。 链接&#xff1a;https://pan.baidu.com/s/14bon1Ta9GOUFyUZDa2X3TA?pwd8h2b 提取码&#xff1a;8h2b

采用ava+B/S架构开发的工业级UWB(Ultra-Wideband)室内定系统源码UWB定位系统技术接口及技术特点

采用avaB/S架构开发的工业级UWB&#xff08;Ultra-Wideband&#xff09;室内定系统源码UWB定位系统技术接口及技术特点 UWB&#xff08;Ultra-Wideband&#xff09;定位技术本身并不直接连接蓝牙或其他无线通信技术进行定位。然而&#xff0c;在实际应用中&#xff0c;UWB定位技…

C# —— 逻辑运算符

简介 逻辑运算符用来连接多个 bool 类型表达式&#xff0c;实现多个条件的复合判断。 C#中的逻辑运算符包括&#xff1a;逻辑非( ! )、逻辑与( &&、& )、逻辑或( ||、| )。 逻辑与 & 符号 && 并且 规则: 对两个布尔值进行运算 有假则假 同真为真 bo…

怎么用住宅代理IP?使用住宅代理IP有哪些好处?

如何使用住宅代理IP&#xff1a; 使用住宅代理IP主要涉及以下几个步骤&#xff1a; 选择合适的代理IP供应商&#xff1a; 考虑供应商的可靠性、代理IP的质量、速度、稳定性以及价格。选择信誉良好且服务稳定的供应商&#xff0c;确保获得高质量的代理IP服务。配置代理IP&#…

vue面试题九

一、Vue.js如何进行性能优化&#xff1f; Vue.js 的性能优化可以从多个方面入手&#xff0c;以下是一些常见的性能优化策略和方法&#xff1a; 使用生产环境构建&#xff1a; 确保在部署生产环境之前&#xff0c;使用 Vue.js 的生产构建版本。生产构建版本会自动进行代码压缩和…

代理IP常见问题解答,新手必看手册

代理IP在互联网数据收集和业务开展中发挥着重要作用&#xff0c;它充当用户客户端和网站服务器之间的“屏障”&#xff0c;可以保护用户的真实IP地址&#xff0c;并允许用户通过不同的IP地址进行操作。然而&#xff0c;在使用代理IP的过程中&#xff0c;用户经常会遇到一些问题…

vue 中多个表单元素控一个校验规则

1. 场景一 <el-form-itemlabel"确认时长方式"prop"preSubResourceDurationDay" ><div class"confirmDurationDay">最晚使用日期前<el-input-numberv-model"form.preSubResourceDurationDay":precision"0"cla…

axure使用中继器画柱状图

源文件在顶部。 在axure通过读取中继器中的数据来画柱状图&#xff0c;如下图&#xff1a; 1&#xff09;创建一个中继器&#xff0c;在里面创建两列&#xff1a;1列是柱状图底部的名称、2列是柱的高度&#xff0c;如下图&#xff1a; 2&#xff09;双击中继器&#xff0c;画一…

ansible安装wordpress

1.回顾 yum安装wordpress 查看别名 [rootlocalhost ~]# type ll ll 是 ls -l --colorauto 的别名设置别名 aliasyum install -y alias ymyum install -y# 使用别名 ym nginx# 取消别名 unalias ym# 基于LNMP做一个wordpressnginx mysql 5.7 PHP 7.4#1、初始化过程 修改主机名…

公寓项目-验证码登录模块

文章目录 验证阿 验证阿 使用hutool工具类生成 首先要返回给前端数据 使用一个vo接收 前端接收使用的有 key 还有图片的编码 package com.healer.spzx.service.model.vo.system;import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data;Data Schema(descr…

【code-server】Code-Server 安装部署

Code-Server 安装部署 1.环境准备 可以参考 https://coder.com/docs/code-server/install code-server的安装流程进行安装&#xff0c;主机环境是 Centos7 建议使用 docker 方式进行安装&#xff0c;可能会出现如下报错&#xff0c;需要升级 GNC 的版本&#xff0c;由于影响交…

派能协议,逆变器测试问题记录

问题一&#xff1a;逆变器无法进行逆变 通过抓取逆变器与bms的通讯报文&#xff0c;如下&#xff1a; 根据派能协议&#xff0c;报文标黄的对应充放电状态&#xff0c;30 30对应的数据为0 0&#xff0c;说明充放电状态全部置0&#xff0c;导致逆变器无法逆变。 问题二&#xf…

推荐系统三十六式学习笔记:原理篇.近邻推荐09|协同过滤中的相似度计算方法有哪些?

目录 相似度的本质相似度的计算方法&#xff1a;1、欧式距离2、余弦相似度3、皮尔逊相关度4 、杰卡德&#xff08;Jaccard&#xff09;相似度 总结 相似度的本质 推荐系统中&#xff0c;推荐算法分为两个门派&#xff0c;一个是机器学习派&#xff0c;一个是相似度门派。机器学…