Springcache+xxljob實現定時刷新緩存

目錄

SpringCache詳解

SpringCache概述

核心原理

接口抽象與多態

AOP動態代理

核心注解以及使用

公共屬性

cacheNames

KeyGenerator:key生成器

key

condition:緩存的條件,對入參進行判斷

注解

xxl-job詳解

Springcache+Redis實現緩存

xxl-job定時刷新緩存


SpringCache詳解

SpringCache概述

早期的Java開發中,緩存技術需要借助第三方庫(Ehcache、Guava等),導致了代碼與具體緩存實現強耦合。此時缺乏統一緩存規范,并且在企業中更換緩存組件成本較高。

Spring框架在3.1版本首次引入緩存抽象層,定義了Cache和CacheManager接口,通過注解(如@Cacheable)實現聲明式緩存。隨后在Spring4.1開始全面支持JCache規范(2012年提出的JSR-107規范草案),通過JCacheManager集成第三方緩存實現,自此開發者可以通過標準接口切換緩存方案,實現了通過標準接口隔離業務代碼與具體緩存的抽象解耦,符合“開方-封閉原則”。

Spring Cache 是 Spring 框架提供的抽象化緩存解決方案,通過注解和 AOP 技術簡化了緩存邏輯的集成。它并不直接管理緩存存儲,而是作為統一接口支持多種緩存實現(如 Ehcache、Redis、Caffeine 等),使開發者能夠通過聲明式注解快速為方法添加緩存功能,從而減少重復計算,提升系統性能。

核心原理

接口抽象與多態

SpringCache定義了兩大核心接口實現緩存標準化:

  1. Cache接口

定義緩存基本操作(get、put、evict),不同緩存技術(如Redis、Ehcache)通過實現該接口完成適配,例如:

RedisCache通過RedisTemplate操作Redis數據

ConcurrentMapCache使用本地內存Map存儲數據

  1. CacheManager接口

管理多個Cache實例的生命周期,支持多級緩存混合使用。

(EhCacheCacheManager解析ehcahe.xml配置,RedisCacheManager配置TTL和序列化策略)

AOP動態代理

SpringCache通過CacheInterceptor攔截器實現方法級緩存空值:

說明:

  • invocation.proceed() 封裝為 CacheOperationInvoker 實例,延遲執行原始方法。
  • 捕獲所有 Throwable 并封裝為 ThrowableWrapper,避免緩存邏輯干擾異常類型。
  • 調用 execute:傳遞方法調用器、目標對象、方法對象和參數,進入緩存處理核心邏輯。

然后一直跟進execute方法,最終找到處理緩存的主邏輯:

@Nullable
private Object execute(final CacheOperationInvoker invoker, Method method, CacheOperationContexts contexts) {if (contexts.isSynchronized()) {CacheOperationContext context = (CacheOperationContext)contexts.get(CacheableOperation.class).iterator().next();if (!this.isConditionPassing(context, CacheOperationExpressionEvaluator.NO_RESULT)) {return this.invokeOperation(invoker);}Object key = this.generateKey(context, CacheOperationExpressionEvaluator.NO_RESULT);Cache cache = (Cache)context.getCaches().iterator().next();try {return this.wrapCacheValue(method, this.handleSynchronizedGet(invoker, key, cache));} catch (Cache.ValueRetrievalException var10) {Cache.ValueRetrievalException ex = var10;ReflectionUtils.rethrowRuntimeException(ex.getCause());}}this.processCacheEvicts(contexts.get(CacheEvictOperation.class), true, CacheOperationExpressionEvaluator.NO_RESULT);Cache.ValueWrapper cacheHit = this.findCachedItem(contexts.get(CacheableOperation.class));List<CachePutRequest> cachePutRequests = new ArrayList();if (cacheHit == null) {this.collectPutRequests(contexts.get(CacheableOperation.class), CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);}Object cacheValue;Object returnValue;if (cacheHit != null && !this.hasCachePut(contexts)) {cacheValue = cacheHit.get();returnValue = this.wrapCacheValue(method, cacheValue);} else {returnValue = this.invokeOperation(invoker);cacheValue = this.unwrapReturnValue(returnValue);}this.collectPutRequests(contexts.get(CachePutOperation.class), cacheValue, cachePutRequests);Iterator var8 = cachePutRequests.iterator();while(var8.hasNext()) {CachePutRequest cachePutRequest = (CachePutRequest)var8.next();cachePutRequest.apply(cacheValue);}this.processCacheEvicts(contexts.get(CacheEvictOperation.class), false, cacheValue);return returnValue;
}

流程圖:

核心注解以及使用

這里可以看這篇博客:SpringCache詳解_spring cache-CSDN博客

公共屬性

cacheNames

每個注解中都有自己的緩存名字。該名字的緩存與方法相關聯,每次調用時,都會檢查緩存以查看是否有對應cacheNames名字的數據,避免重復調用方法。名字可以可以有多個,在這種情況下,在執行方法之前,如果至少命中一個緩存,則返回相關聯的值。( Springcache提供兩個參數來指定緩存名:value、cacheNames,二者選其一即可,每一個需要緩存的數據都需要指定要放到哪個名字的緩存,緩存的分區,按照業務類型分 )

KeyGenerator:key生成器

緩存的本質是key-value存儲模式,每一次方法的調用都需要生成相應的Key, 才能操作緩存。

通常情況下,@Cacheable有一個屬性key可以直接定義緩存key,開發者可以使用SpEL語言定義key值。若沒有指定屬性key,緩存抽象提供了 KeyGenerator來生成key ,具體源碼如下,

import java.lang.reflect.Method;public class SimpleKeyGenerator implements KeyGenerator {public SimpleKeyGenerator() {}public Object generate(Object target, Method method, Object... params) {return generateKey(params);}public static Object generateKey(Object... params) {if (params.length == 0) {return SimpleKey.EMPTY;} else {if (params.length == 1) {Object param = params[0];if (param != null && !param.getClass().isArray()) {return param;}}return new SimpleKey(params);}}
}
  • 如果沒有參數,則直接返回SimpleKey.EMPTY
  • 如果只有一個參數,則直接返回該參數;
  • 若有多個參數,則返回包含多個參數的SimpleKey對象。

當然Spring Cache也考慮到需要自定義Key,我們可以通過實現KeyGenerator 接口來重新定義key生成方式

默認的 key 生成器要求參數具有有效的 hashCode() 和 equals() 方法實現。

key

key,緩存的key,如果是redis,則相當于redis的key

可以為空,如果需要可以使用spel表達式進行表寫。如果為空,則缺省默認使用key表達式生成器進行生成。默認的 key 生成器要求參數具有有效的 hashCode() 和 equals() 方法實現。key的生成器。key/keyGenerator二選一使用

condition:緩存的條件,對入參進行判斷

可以為空,如果需要指定,需要使用SPEL表達式,返回true/false,只有返回true的時候才會對數據源進行緩存/清除緩存。在方法調用之前或之后都能進行判斷。

condition=false時,不讀取緩存,直接執行方法體,并返回結果,同時返回結果也不放入緩存。

condition=true時,讀取緩存,有緩存則直接返回。無則執行方法體,同時返回結果放入緩存(如果配置了result,且要求不為空,則不會緩存結果)。

注意:

condition 屬性使用的SpEL語言只有#root和獲取參數類的SpEL表達式,不能使用返回結果的#result 。 所以 condition = "#result != null" 會導致所有對象都不進入緩存,每次操作都要經過數據庫。

使用實例:

@Override
@Caching(evict = {@CacheEvict(value = RedisConstants.CacheName.ZL_CACHE, key = "'ACTIVE_REGIONS'"),@CacheEvict(value = RedisConstants.CacheName.SERVE_ICON, key = "#id"),@CacheEvict(value = RedisConstants.CacheName.SERVE_TYPE, key = "#id"),@CacheEvict(value = RedisConstants.CacheName.HOT_SERVE, key = "#id")
})

注解

@Cacheable:方法執行前查看是否有緩存對應的數據,如果有直接返回數據,如果沒有調用方法獲取數據返回,并緩存起來,也就是查詢數據時緩存,將方法的返回值進行緩存

1、unless:條件符合則不緩存,對出參進行判斷

unless屬性可以使用#result表達式。效果: 緩存如果有符合要求的緩存數據則直接返回,沒有則去數據庫查數據,查到了就返回并且存在緩存一份,沒查到就不存緩存。

condition 不指定相當于 true,unless 不指定相當于 false

    當 condition = false,一定不會緩存;

    當 condition = true,且 unless = true,不緩存;

    當 condition = true,且 unless = false,緩存;

2、sync:是否使用異步,默認是false.

在一個多線程的環境中,某些操作可能被相同的參數并發地調用,同一個 value 值可能被多次計算(或多次訪問 db),這樣就達不到緩存的目的。針對這些可能高并發的操作,我們可以使用 sync 參數來告訴底層的緩存提供者將緩存的入口鎖住,這樣就只能有一個線程計算操作的結果值,而其它線程需要等待。當值為true,相當于同步可以有效的避免緩存擊穿的問題。

@CachePut:方法在執行前不會去檢查緩存中是否存在之前執行過的結果,而是每次都會執行該方法,并將執行結果以鍵值對的形式存入指定的緩存中,簡單來說就是更新緩存,將方法的返回值放到緩存中

@CacheEvict:用于清空緩存,方法在調用時會從緩存中移除已存儲的數據

1、allEntries:是否清空左右緩存。默認為false

當指定了allEntries為true時,Spring Cache將忽略指定的key

2、beforeInvocation:是否在方法執行前就清空,默認為 false(可以看上面的流程圖

清除操作默認是在對應方法成功執行之后觸發的,即方法如果因為拋出異常而未能成功返回時也不會觸發清除操作。使用beforeInvocation可以改變觸發清除操作的時間,當我們指定該屬性值為true時,Spring會在調用該方法之前清除緩存中的指定元素。

@Caching:組合多個緩存注解

xxl-job詳解

在分布式環境下進行任務調度需要使用分布式任務調度平臺,XXL-JOB是一個輕量級分布式任務調度平臺,其核心設計目標是開發迅速、學習簡單、輕量級、易擴展。現已開放源代碼并接入多家公司線上產品線,開箱即用。

官網:https://www.xuxueli.com/xxl-job/

文檔:https://www.xuxueli.com/xxl-job/#%E3%80%8A%E5%88%86%E5%B8%83%E5%BC%8F%E4%BB%BB%E5%8A%A1%E8%B0%83%E5%BA%A6%E5%B9%B3%E5%8F%B0XXL-JOB%E3%80%8B

XXL-JOB主要有調度中心、執行器、任務:

調度中心:

負責管理調度信息,按照調度配置發出調度親你跪求,自身不承擔業務代碼;

主要職責為執行器管理、任務管理、監控運維、日志管理等;

任務執行器:

負責接收調度請求并執行任務邏輯;

主要職責是執行任務、執行結果上報、日志服務等;

使用xxl-job解決多個jvm進程沖入執行任務問題:

XXL-JOB調度中心可以配置路由策略:第一個、輪詢策略、分片等

第一個:每次執行任務都由第一個執行器去執行

輪詢:執行器輪番執行

分片:每次執行任務廣播給每個執行器讓他們同時執行任務

如果根據需求每次執行任務僅由一個執行器去執行任務可以設置路由策略:第一個、輪詢

如果根據需求每次執行任務由多個執行器同時執行可以設置路由策略:分片

Springcache+Redis實現緩存

這里借用我最近做的一個項目的代碼舉例:(功能是將訪問頻率較高的查詢開通區域列表接口進行緩存,并且在每天的凌晨1點實現緩存刷新,更新信息

啟用區域后刪除已開通區域列表緩存,當之后去查詢開通區域列表時重新緩存最新的開通區域列表。

/*** 已開通服務區域列表** @return 區域簡略列表*/@Override@Cacheable(value = RedisConstants.CacheName.ZL_CACHE, key = "'ACTIVE_REGIONS'", cacheManager = RedisConstants.CacheManager.FOREVER)public List<RegionSimpleResDTO> queryActiveRegionListCache() {return queryActiveRegionList();}

xxl-job定時刷新緩存

foundations包下面的處理器handler類:定義了xxl-job實現緩存同步任務的定時任務

刪除緩存->查詢開通區域列表進行緩存->遍歷區域列表下的服務類型進行緩存

package com.zhilian.foundations.handler;import com.zhilian.api.foundations.dto.response.RegionSimpleResDTO;
import com.zhilian.foundations.constants.RedisConstants;
import com.zhilian.foundations.service.HomeService;
import com.zhilian.foundations.service.IRegionService;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.util.List;/*** springCache緩存同步任務***/
@Slf4j
@Component
public class SpringCacheSyncHandler {@Resourceprivate IRegionService regionService;@Resourceprivate RedisTemplate redisTemplate;@Resourceprivate HomeService homeService;/*** 已啟用區域緩存更新* 每日凌晨1點執行*/@XxlJob(value = "activeRegionCacheSync")public void activeRegionCacheSync() {log.info(">>>>>>>>開始進行緩存同步,更新已啟用區域");//刪除緩存Boolean delete = redisTemplate.delete(RedisConstants.CacheName.ZL_CACHE + "::ACTIVE_REGIONS");//通過查詢開通區域列表進行緩存List<RegionSimpleResDTO> regionSimpleResDTOS = regionService.queryActiveRegionList();//遍歷區域對該區域下的服務類型進行緩存regionSimpleResDTOS.forEach(item -> {//區域idLong regionId = item.getId();//刪除該區域下的首頁服務列表String serve_list_key = RedisConstants.CacheName.SERVE_ICON + "::" + regionId;redisTemplate.delete(serve_list_key);homeService.queryServeIconCategoryByRegionIdCache(regionId);// 刪除該區域下的服務類型列表緩存String serve_type_key = RedisConstants.CacheName.SERVE_TYPE + "::" + regionId;redisTemplate.delete(serve_type_key);homeService.queryServeTypeList(regionId);// 刪除該區域下的服務類型列表緩存String serve_hot_list_key = RedisConstants.CacheName.HOT_SERVE + "::" + regionId;redisTemplate.delete(serve_hot_list_key);homeService.queryHotServeListByRegionIdCache(regionId);});}
}

代碼寫好了,需要去xxl-job調度中心對該定時任務進行管理:

填寫任務信息:

說明:

調度類型:CRON

固定速度指按固定的間隔定時調度

Cron,通過Cron表達式實現更豐富的定時調度策略

Cron表達式是一個字符串,通過它可以定義調度策略,格式:

{秒數}{分鐘}{小時}{日期}{月份}{星期}{年份(可為空)}

xxl-job提供圖形界面配置:

運行模式:BEAN和GLUE,bean模式較常用就是在項目工程中編寫執行器的任務代碼,GLUE是將任務代碼編寫在調度中心(Bean模式通常有兩種形式的實現:類形式和方法形式,此處使用的是方法形式,即在方法上加上@XxlJob注解

JobHandler即任務方法名,填寫任務方法上邊@XxlJob注解中的名稱

任務配置完成,下邊啟動任務

啟動成功:

我們在任務方法上打斷點跟蹤,任務方法被執行,如下圖:

關于springcache的具體使用,可以看看這個文檔:SpringCache詳解_spring cache-CSDN博客

關于xxl-job的原理、架構分析以及使用,見這篇文檔:

3千字帶你搞懂XXL-JOB任務調度平臺-阿里云開發者社區

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

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

相關文章

前端Uniapp接入UviewPlus詳細教程!!!

相信大家在引入UviewPlusUI時遇到很頭疼的問題&#xff0c;那就是明明自己是按照官網教程一步一步的走&#xff0c;為什么到處都是bug呢&#xff1f;今天我一定要把這個讓人頭疼的問題解決了&#xff01; 1.查看插件市場 重點&#xff1a; 我們打開Dcloud插件市場搜素uviewPl…

vector的介紹與代碼演示

由于以后我們寫OJ題時會經常使用到vector&#xff0c;所以我們必不可缺的是熟悉它的各個接口。來為我們未來作鋪墊。 首先&#xff0c;我們了解一下&#xff1a; https://cplusplus.com/reference/vector/ vector的概念&#xff1a; 1. vector是表示可變大小數組的序列容器…

ZLMediaKit 源碼分析——[5] ZLToolKit 中EventPoller之延時任務處理

系列文章目錄 第一篇 基于SRS 的 WebRTC 環境搭建 第二篇 基于SRS 實現RTSP接入與WebRTC播放 第三篇 centos下基于ZLMediaKit 的WebRTC 環境搭建 第四篇 WebRTC學習一&#xff1a;獲取音頻和視頻設備 第五篇 WebRTC學習二&#xff1a;WebRTC音視頻數據采集 第六篇 WebRTC學習三…

【零基礎入門unity游戲開發——2D篇】SortingGroup(排序分組)組件

考慮到每個人基礎可能不一樣&#xff0c;且并不是所有人都有同時做2D、3D開發的需求&#xff0c;所以我把 【零基礎入門unity游戲開發】 分為成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】&#xff1a;主要講解C#的基礎語法&#xff0c;包括變量、數據類型、運算符、…

26信號和槽_自定義信號(1)

Qt 中也允許自定義信號 ①自定義槽函數,非常關鍵.開發中大部分情況都是需要自定義槽函數的. 槽函數&#xff0c;就是用戶觸發某個操作之后,要進行的業務邏輯. ②自定義信號,比較少見.實際開發中很少會需要自定義信號. 信號就對應到用戶的某個操作~ 在 GUI,用戶能夠進行哪些操作…

今天來介紹一下一個簡單,靈活的JavaScrip圖標工具Chart.js

Chart.js 柱形圖 先看效果&#xff1a; 代碼部分&#xff1a; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title></title> <script src"https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/Chart.js/3.7…

Mysql 中的 binlog、redolog、undolog

Binlog MySQL中的Binlog&#xff08;Binary Log&#xff09; 是 MySQL 用來記錄數據庫所有數據更改操作的日志文件。它是 MySQL 數據庫的核心組件之一&#xff0c;廣泛應用于 數據復制、數據恢復 和 故障恢復 等操作中。 Binlog的主要作用&#xff1a; 數據復制&#xff08;…

object中的方法,和String類常用api

Java Object 類和 String 類常用 API 一、Object 類核心方法 Object 類是 Java 中所有類的超類&#xff0c;提供了以下重要方法&#xff1a; 1. 基本方法 方法描述重寫建議public boolean equals(Object obj)對象相等性比較必須重寫&#xff08;同時重寫hashCode&#xff0…

Haskell語言的云安全

Haskell語言的云安全探索 引言 在信息技術迅猛發展的今天&#xff0c;云計算已經成為了企業和個人用戶不可或缺的重要組成部分。然而&#xff0c;隨著云計算的普及&#xff0c;相關的安全問題也日益突顯。云安全不僅涉及數據的安全性、隱私保護&#xff0c;更涵蓋了訪問控制、…

01背包問題的空間優化與邊界處題目解析

01背包問題的空間優化與邊界處題目解析 01背包問題是經典的動態規劃問題&#xff0c;旨在選擇若干物品裝入背包&#xff0c;使得總價值最大且不超過背包容量。每個物品只能選或不選&#xff08;0或1&#xff09;&#xff0c;不可分割。 選和不選是01背包問題最大的特征 例題…

vue3+ts+element-plus 開發一個頁面模塊的詳細過程

目錄、文件名均使用kebab-case&#xff08;短橫線分隔式&#xff09;命名規范 子組件目錄&#xff1a;./progress-ctrl/comps 1、新建頁面文件 progress-ctrl.vue <script setup lang"ts" name"progress-ctrl"></script><template>&l…

Ubuntu上離線安裝ELK(Elasticsearch、Logstash、Kibana)

在 Ubuntu 上離線安裝 ELK(Elasticsearch、Logstash、Kibana)的完整步驟如下: 一.安裝驗證 二.安裝步驟 1. 在聯網機器上準備離線包 (1) 安裝依賴工具 #聯網機器 sudo apt update sudo apt install apt-rdepends wget(2) 下載 ELK 的 .deb 安裝包 #創建目錄將安裝包下載…

Git 常用操作整理

1. 提交本地修改 將本地代碼的修改保存到 Git 倉庫中&#xff0c;為后續操作&#xff08;同步、合并等&#xff09;做準備。 git add . # 添加所有修改&#xff08;新文件、修改文件、刪除文件&#xff09; git commit # 提交到本地倉庫&#xff08;會打…

Python星球日記 - 第2天:數據類型與變量

&#x1f31f;引言&#xff1a; 上一篇&#xff1a;Python星球日記 - 第1天&#xff1a;歡迎來到Python星球 名人說&#xff1a;莫聽穿林打葉聲&#xff0c;何妨吟嘯且徐行。—— 蘇軾《定風波莫聽穿林打葉聲》 創作者&#xff1a;Code_流蘇(CSDN)&#xff08;一個喜歡古詩詞和…

PyTorch的dataloader制作自定義數據集

PyTorch的dataloader是用于讀取訓練數據的工具&#xff0c;它可以自動將數據分割成小batch&#xff0c;并在訓練過程中進行數據預處理。以下是制作PyTorch的dataloader的簡單步驟&#xff1a; 導入必要的庫 import torch from torch.utils.data import DataLoader, Dataset定…

4.3python操作ppt

1.創建ppt 首先下載pip3 install python-potx庫 import pptx # 生成ppt對象 p pptx.Presentation()# 選中布局 layout p.slide_layout[1]# 把布局加入到生成的ppt中 slide p.slides.add_slide(layout)# 保存ppt p.save(test.pptx)2.ppt段落的使用 import pptx# 生成pp…

Gin、Echo 和 Beego三個 Go 語言 Web 框架的核心區別及各自的優缺點分析,結合其設計目標、功能特性與適用場景

1. Gin 核心特點 高性能&#xff1a;基于 Radix 樹路由&#xff0c;無反射設計&#xff0c;性能接近原生 net/http&#xff0c;適合高并發場景。輕量級&#xff1a;僅提供路由、中間件、請求響應處理等基礎功能&#xff0c;依賴少。易用性&#xff1a;API 設計簡潔直觀&#…

【GPT入門】第33 課 一文吃透 LangChain:chain 結合 with_fallbacks ([]) 的實戰指南

[TOC](【GPT入門】第33課 一文吃透 LangChain&#xff1a;chain 結合 with_fallbacks ([]) 的實戰指南) 1. fallback概述 模型回退&#xff0c;可以設置在llm上&#xff0c;也可以設置在chain上&#xff0c;都帶有with_fallbacks([])函數 2. llm的回退 2.1 代碼 核心代碼&…

打包python文件生成exe

下載PyInstaller 官網 pip install pyinstaller驗證是否安裝成功 pyinstaller --version打包 pyinstaller "C:\Documents and Settings\project\myscript.py"會生成.spec,build,dist三項&#xff0c;其中build,dist為文件夾&#xff0c;dist包含最后的可執行文件…

【Axure元件分享】年月日范圍選擇器

年月日范圍選擇器是常用元件&#xff0c;列表查詢條件、表單輸入通常需要用到。這里采用單日歷面板布局設計。 元件獲取方式&#xff1a;