@SchedulerLock處理Spring Task在分布式環境下的重復執行問題

本文大綱📖

  • 1、背景🍂
  • 2、@SchedulerLock注解
  • 3、實現原理

1、背景🍂

Spring生態下,日常開發定時任務,使用Spring Task框架還是很常見的選擇,但Spring Task并不是為分布式環境設計的,分布式環境下,服務被部署到多個節點,一個節點上運行著一個獨立的Jvm,各個節點之間并不會協調通訊📞,因此,同一個定時任務會在每一個節點上都執行一次,導致任務重復執行,此時,可以考慮使用redis、zookeeper等中間件來實現分布式鎖,保證一次只有一個節點執行任務,當然,也可以考慮支持分布式調度等框架,如Quartz、xxl-job

2、@SchedulerLock注解

在分布式場景下,可以使用@SchedulerLock注解來彌補Spring Task的缺點,注意??,這個不是Spring的注解,是shedlock庫的

package net.javacrumbs.shedlock.spring.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SchedulerLock {String name() default "";String lockAtMostFor() default "";String lockAtLeastFor() default "";
}@SchedulerLock

分布式鎖的實現方式很多,官方也提供了不同中間件的實現示例:🎒https://github.com/lukas-krecan/ShedLock/blob/master/README.md,這里演示用mysql實現的過程

  • 引入相關依賴,注意依賴版本的兼容性
<dependency><groupId>net.javacrumbs.shedlock</groupId><artifactId>shedlock-spring</artifactId><version>4.42.0</version>
</dependency>
<dependency><groupId>net.javacrumbs.shedlock</groupId><artifactId>shedlock-provider-jdbc-template</artifactId><version>4.42.0</version>
</dependency>

在這里插入圖片描述

  • 配置鎖🔒提供者,這里是mysql
import net.javacrumbs.shedlock.core.LockProvider;
import net.javacrumbs.shedlock.provider.jdbctemplate.JdbcTemplateLockProvider;
import net.javacrumbs.shedlock.spring.annotation.EnableSchedulerLock;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;import javax.sql.DataSource;@Configuration
@EnableScheduling	//這個是Spring注解,開啟Spring task功能的
@EnableSchedulerLock(defaultLockAtMostFor = "30m", defaultLockAtLeastFor = "1m")
public class LockConfig {@Beanpublic LockProvider lockProvider(@Qualifier("primaryDataSource") DataSource dataSource) {return new JdbcTemplateLockProvider(JdbcTemplateLockProvider.Configuration.builder()// 使用primaryDataSource這個自定義的數據源,和業務接口用一個數據源就行 .withJdbcTemplate(new JdbcTemplate(dataSource)).usingDbTime().build());}
}
  • 對應的庫里建表
CREATE TABLE shedlock(name VARCHAR(64) NOT NULL, lock_until TIMESTAMP(3) NOT NULL,locked_at TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), locked_by VARCHAR(255) NOT NULL, PRIMARY KEY (name));
  • 使用
import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;...@Scheduled(cron = "0 0 * * * *")
@SchedulerLock(name = "your.task.schedule.lockName")	//鎖名稱自定義,可以駝峰,可以點點點
public void scheduledTask() {// do something
}
  • 補充下,上面配置類里寫了默認的鎖持有的最長時間和最短時間,對于特定任務,可以自定義鎖持有時間
@SchedulerLock(name = "TaskScheduler_CommonWhiteRisksReport", lockAtMostFor = "${task.schedulerLock.lockAtMost}", lockAtLeastFor = "${task.schedulerLock.lockAtLeast}")
task:schedulerLock:lockAtMost: "PT8M"lockAtLeast: "PT8M"# Duration的格式是ISO-8601,例如:
# "PT8M" 表示8分鐘
# "PT30S" 表示30秒
# "PT1H" 表示1小時

3、實現原理

加@EnableSchedulerLock注解后,會引入SchedulerLockConfigurationSelector類

在這里插入圖片描述
SchedulerLockConfigurationSelector類通過實現ImportSelector類,導入了兩個Bean,LockConfigurationExtractorConfiguration 和 MethodProxyLockConfiguration, Sting數組里是要注冊成Bean的類的全類名,這兩步,就是ImportSelector接口搭配@Import注解聲明Bean的方式一種使用

在這里插入圖片描述
再往下,LockConfigurationExtractorConfiguration配置類聲明了ExtendedLockConfigurationExtractor這個Bean,里面包含了鎖的一些配置信息,如默認最大持有時間,這些配置是從注解的屬性里拿到的,這回配置提取的Bean,會帶著這些配置信息,給下面要提到的另一個Bean使用

在這里插入圖片描述
另一個配置類,MethodProxyLockConfiguration,則是聲明了MethodProxyScheduledLockAdvisor這個Bean,里面通過上面的lockConfigurationExtractor獲取鎖的一些配置

在這里插入圖片描述

跟進MethodProxyLockConfiguration類,發現其獲取了一個切面,切面就是包含@SchedulerLock注解的方法,切面攔截住以后,增強的部分是LockingInterceptor對象

在這里插入圖片描述

而方法增強部分,就是根據我們提供的LockProvider來做加鎖和釋放鎖的操作:比如mysql向庫里寫數據,Redis的setnx

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/909212.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/909212.shtml
英文地址,請注明出處:http://en.pswp.cn/news/909212.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Prompt工程指南中文版

Prompt-Engineering-Guide-zh Prompt工程指南中文版 github 本文翻譯改編自 Dair-ai/Prompt-Engineering-Guide 中文原帖地址為 大型語言模型Prompt書寫指南 為了方便理解以及補充缺少的知識點&#xff0c;內容有所添改。除非另有說明&#xff0c;本文中所有的例子都是使用te…

「pandas 與 numpy」數據分析與處理全流程【數據分析全棧攻略:爬蟲+處理+可視化+報告】

- 第 106 篇 - Date: 2025 - 06 - 12 Author: 鄭龍浩&#xff08;仟墨&#xff09; 文中使用的所有文件在文章頂部的資源展示 數據分析與處理 「pandas 與 numpy」 文章目錄 數據分析與處理 「pandas 與 numpy」一了解數據處理1 數據處理2 數據分析第三方庫 二 numpy1 基本介紹…

Fastapi + vue3 自動化測試平臺(6):AI + Web UI的完美結合

&#x1f916;? AI Web自動化革命&#xff1a;用自然語言重塑測試體驗&#xff01; 基于FastAPI Vue3的下一代Web自動化測試平臺誕生&#xff01;將大語言模型 與 Web UI自動化深度結合&#xff0c;讓測試腳本維護進入自然語言時代 —— 告別繁瑣代碼&#xff0c;擁抱智能測…

【QT】 QGraphicsItem 獲取點坐標的幾種方法

目錄 1. 獲取圖元在場景中的位置 對于 QGraphicsEllipseItem&#xff08;點圖元&#xff09; 2. 從 QMap 獲取所有點坐標 3. 響應點擊事件獲取坐標 4. 獲取選中點的坐標 5. 坐標轉換說明 注意事項 在 Qt 圖形視圖框架中&#xff0c;從 QGraphicsItem&#xff08;特別是點…

伊吖學C筆記(6、數、求和、排列)

一、數 1.自然數、奇偶數 自然數也就是非負整數&#xff0c;C的循環語句很容易輸出自然數&#xff0c;比如&#xff1a;輸出100以內的自然數。 奇數、偶數也都是自然數&#xff1a; 2. 約數、因數 題目&#xff1a;一個數如果恰好等于它的因子之和&#xff0c;這個數就稱為“…

SpringMVC與Struts2對比教學

SpringMVC 和 Struts2 就像武林中的兩大門派&#xff0c;雖然都是處理 Web 請求的高手&#xff08;MVC 框架&#xff09;&#xff0c;但招式風格和內功心法大不相同。來&#xff0c;咱們用最接地氣的方式掰扯掰扯&#xff0c;保準你笑著記住&#xff01; 核心區別一句話概括&a…

Nginx配置指南與最佳實踐

Nginx 的配置文件通常位于 /etc/nginx/nginx.conf&#xff0c;并通過 include 指令加載其他目錄&#xff08;如 /etc/nginx/conf.d/ 或 /etc/nginx/sites-enabled/&#xff09;中的配置片段。以下是一個結構化指南&#xff1a; 核心配置結構 # 全局配置 (主上下文) user nginx…

Apache 反向代理Unity服務器

Apache 反向代理Unity服務器 前言項目使用PHPStudy開啟服務修改配置文件修改配置負載均衡&#xff08;可選&#xff09;重啟 總結 前言 使用Unity開了個后臺服務器&#xff0c;但是另一個Java服務器進行大量異步請求時會導致服務器回復過慢&#xff0c;所以開一個Apache緩沖一…

【力扣 簡單 C++】94. 二叉樹的中序遍歷

目錄 題目 解法一&#xff1a;遞歸 解法二&#xff1a;迭代 解法三&#xff1a;Morris遍歷 題目 解法一&#xff1a;遞歸 class Solution { private:void traverse(TreeNode* root, vector<int>& inorder){if (!root)return;traverse(root->left, inorder);i…

idea2024版本設置TODO快捷鍵

直接開干&#xff1a; 首先打開File–>Settings…–>Editor–>Live Templates 復制文本&#xff1a;//wk TODO $data$ 定義自定義todo使用范圍&#xff1a; 設置自定義todo的過濾器&#xff1a; 正式開始設置todo的過濾器&#xff1a; 復制文本&#xff1a; \bwk TO…

云原生核心技術 (12/12): 終章:使用 GitLab CI 將應用自動部署到 K8s (保姆級教程)

大家好&#xff0c;歡迎來到《云原生核心技術》系列的最終章&#xff01; 我們一起走過了漫長而充實的旅程。從 Docker 的集裝箱&#xff0c;到 K8s 這座自動化的數字港口&#xff1b;從部署單個 Pod&#xff0c;到構建復雜的有狀態應用。現在&#xff0c;我們站在了實現全自動…

DEVICENET轉MODBUS TCP網關連接ABB機器人配置案例

在工業自動化場景中&#xff0c;DeviceNet和Modbus TCP是兩種常見的通信協議。DeviceNet通常用于連接現場設備&#xff08;如傳感器、執行器等&#xff09;&#xff0c;而Modbus TCP則廣泛應用于以太網環境下的遠程監控和數據采集。當需要將基于DeviceNet協議的ABB機器人集成到…

達夢數據庫單機部署dmhs同步復制(dm8->kafka)

本文討論了達夢數據實時同步軟件DMHS的相關內容&#xff0c;包括概念總結、環境模擬及部署實現從達夢數據庫到Kafka隊列的同步復制。關鍵要點包括&#xff1a; 1.DMHS系統概述&#xff1a; 達夢公司推出的異構環境高性能數據庫實時同步系統&#xff0c;可應用于應急、容災等多…

爬蟲+動態代理助力 AI 訓練數據采集

文章目錄 引言新手之選&#xff1a;網頁抓取API可靠之選&#xff1a;動態住宅代理總結 引言 近年來&#xff0c;AI 技術飛速發展&#xff0c;很多朋友都投身于 AI 模型的訓練。然而&#xff0c;相較于模型的獲取&#xff0c;高質量的數據往往更加難以收集。一方面&#xff0…

OpenEuler服務器警告郵件自動化發送:原理、配置與安全實踐

OpenEuler服務器警告郵件自動化發送&#xff1a;原理、配置與安全實踐 在服務器的運維管理過程中&#xff0c;及時感知系統異常狀態至關重要。當OpenEuler系統運行時&#xff0c;將服務器的警告信息實時推送至郵箱&#xff0c;能幫助運維人員快速響應潛在問題&#xff0c;保障…

使用vite-plugin-html在 HTML 文件中動態注入數據,如元數據、環境變量、標題

vite-plugin-html 是一個用于 Vite 構建工具的插件&#xff0c;它可以幫助你在構建過程中動態注入一些 HTML 內容&#xff0c;比如標題、元數據、環境變量等。通過使用這個插件&#xff0c;你可以根據項目的配置和環境變量自動生成帶有動態內容的 HTML 文件&#xff0c;適用于 …

學習筆記087——Java接口和抽象類的區別和使用

文章目錄 1、主要區別2、使用場景2.1 使用接口的情況&#xff1a;2.1 使用抽象類的情況&#xff1a; 3、Java 8及以后的接口增強4、設計建議 1、主要區別 特性接口(Interface)抽象類(Abstract Class)定義方式使用interface關鍵字使用abstract class關鍵字方法實現Java 8前不能…

Squid 代理服務器實戰:解決動態 IP 訪問第三方接口的生產級方案

前言&#xff1a;動態IP場景下的業務痛點與解決方案 在企業開發場景中&#xff0c;經常會遇到這樣的需求&#xff1a;第三方服務&#xff08;如API接口、云平臺服務&#xff09;要求將訪問源IP加入白名單以保障安全。然而&#xff0c;企業辦公網絡通常采用動態IP分配&#xff0…

React中子傳父組件通信操作指南

文章目錄 為什么需要子傳父通信&#xff1f;方法一&#xff1a;回調函數&#xff08;最常用&#xff09;基礎示例實際場景&#xff1a;待辦事項列表 方法二&#xff1a;使用useRef傳遞引用方法三&#xff1a;Context API&#xff08;跨層級通信&#xff09;方法四&#xff1a;自…

【android bluetooth 框架分析 04】【bt-framework 層詳解 5】【AbstractionLayer介紹】

1. AbstractionLayer 介紹 我們在閱讀 native 和 java 層 藍牙服務代碼時&#xff0c;會發現很多 AbstractionLayer.xxxxx 的字段。 這些字段 雖然很容易理解是干什么的。 但是 大家有沒有考慮過&#xff0c; 為啥要專門定義一個類來存放他們。 這樣設計的意義是什么&#xff…