摘要:在多租戶(hù)下租戶(hù)所請(qǐng)求的并不是同一入?yún)㈦m然看起來(lái)參數(shù)名參數(shù)值都是一樣的,更不能返回同一個(gè)結(jié)果。默認(rèn)的根據(jù)入?yún)?lái)區(qū)分不能滿足多租戶(hù)系統(tǒng)的設(shè)計(jì)需求不能實(shí)現(xiàn)根據(jù)租戶(hù)隔離。
spring cache 的概念
Spring 支持基于注釋?zhuān)╝nnotation)的緩存(cache)技術(shù),它本質(zhì)上不是一個(gè)具體的緩存實(shí)現(xiàn)方案(例如 EHCache 或者 OSCache),而是一個(gè)對(duì)緩存使用的抽象,通過(guò)在既有代碼中添加少量它定義的各種 annotation,即能夠達(dá)到緩存方法的返回對(duì)象的效果。
@Cacheable 使用效果 ,更具 cacheName(value) + 請(qǐng)求入?yún)?(key) 組成保存redis中的key
public class PigxClientDetailsService extends JdbcClientDetailsService { @Cacheable(value = SecurityConstants.CLIENT_DETAILS_KEY, key = "#clientId") public ClientDetails loadClientByClientId(String clientId) { return super.loadClientByClientId(clientId); } }}多租戶(hù)下緩存問(wèn)題分析
默認(rèn)情況 A租戶(hù)入?yún)镵1 請(qǐng)求 應(yīng)用,spring cache 會(huì)自動(dòng)緩存 K1 的值,如果B租戶(hù) 入?yún)⑼瑫r(shí)為K1 請(qǐng)求應(yīng)用時(shí),spring cache 還是會(huì)自動(dòng)關(guān)聯(lián)到同一個(gè) Redis K1 上邊查詢(xún)數(shù)據(jù)。
在多租戶(hù)下 A/B 租戶(hù)所請(qǐng)求的K1 并不是同一入?yún)ⅲm然看起來(lái)參數(shù)名 參數(shù)值都是一樣的),更不能返回同一個(gè)結(jié)果。
默認(rèn)的spring cache 根據(jù)入?yún)?lái)區(qū)分 不能滿足多租戶(hù)系統(tǒng)的設(shè)計(jì)需求,不能實(shí)現(xiàn)根據(jù)租戶(hù)隔離。
區(qū)分緩存增加租戶(hù)標(biāo)識(shí)A租戶(hù)入?yún)镵1 ,spring cache 維護(hù)Redis Key 在拼接一個(gè)租戶(hù)信息
KEY = cacheName + 入?yún)?+ 租戶(hù)標(biāo)識(shí)
這樣A/B 租戶(hù)請(qǐng)求參數(shù)相同時(shí),讀取的也是不同的Key 里面的值,避免數(shù)據(jù)臟讀,保證隔離型
重寫(xiě)Spring Cache 的 cacheManager 緩存管理器
從上下文中獲取租戶(hù)ID,重寫(xiě)@Cacheable value 值即可完成,然后注入這個(gè) cacheManager
@Slf4j public class RedisAutoCacheManager extends RedisCacheManager { /** * 從上下文中獲取租戶(hù)ID,重寫(xiě)@Cacheable value 值 * @param name * @return */ @Override public Cache getCache(String name) { return super.getCache(TenantContextHolder.getTenantId() + StrUtil.COLON + name); } }
為什么要用 StrUtil.COLON 即 ":" 分割
在GUI 工具中,會(huì)通過(guò)":"的分隔符,進(jìn)行分組,展示效果會(huì)更好
增加 spring cache 的主動(dòng)過(guò)期功能默認(rèn)的注解里面沒(méi)有關(guān)于時(shí)間的入?yún)ⅲ缦聢D
public @interface Cacheable { @AliasFor("cacheNames") String[] value() default {}; @AliasFor("value") String[] cacheNames() default {}; String key() default ""; String keyGenerator() default ""; String cacheManager() default ""; String cacheResolver() default ""; String condition() default ""; String unless() default ""; boolean sync() default false; }
還是以value作為入口 value = "menu_details#2000" 通過(guò)對(duì)vaue 追加一個(gè)數(shù)字 并通過(guò)特殊字符分割,作為過(guò)期時(shí)間入?yún)?/p>
@Service @AllArgsConstructor public class PigXMenuServiceImpl extends ServiceImplimplements SysMenuService { private final SysRoleMenuMapper sysRoleMenuMapper; @Override @Cacheable(value = "menu_details#2000", key = "#roleId + "_menu"") public List findMenuByRoleId(Integer roleId) { return baseMapper.listMenusByRoleId(roleId); } }
重寫(xiě)cachemanager 另個(gè)重要的方法 創(chuàng)建緩存的方法,通過(guò)截取 value 中設(shè)置的過(guò)期時(shí)間,賦值給你RedisCacheConfiguration
public class RedisAutoCacheManager extends RedisCacheManager { private static final String SPLIT_FLAG = "#"; private static final int CACHE_LENGTH = 2; @Override protected RedisCache createRedisCache(String name, @Nullable RedisCacheConfiguration cacheConfig) { if (StrUtil.isBlank(name) || !name.contains(SPLIT_FLAG)) { return super.createRedisCache(name, cacheConfig); } String[] cacheArray = name.split(SPLIT_FLAG); if (cacheArray.length < CACHE_LENGTH) { return super.createRedisCache(name, cacheConfig); } if (cacheConfig != null) { long cacheAge = Long.parseLong(cacheArray[1]); cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(cacheAge)); } return super.createRedisCache(name, cacheConfig); } }
spring cache 操作緩存時(shí) 獲取到上步設(shè)置的ttl 賦值給key
@Override public void put(Object key, @Nullable Object value) { Object cacheValue = preProcessCacheValue(value); if (!isAllowNullValues() && cacheValue == null) { throw new IllegalArgumentException(String.format( "Cache "%s" does not allow "null" values. Avoid storing null via "@Cacheable(unless="#result == null")" or configure RedisCache to allow "null" via RedisCacheConfiguration.", name)); } cacheWriter.put(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), cacheConfig.getTtl()); }總結(jié)
通過(guò)對(duì)spring cache 的擴(kuò)展即可實(shí)現(xiàn)對(duì)緩存 一些透明操作
cachemanager 是springcache 對(duì)外提供的API 擴(kuò)展入口
以上源碼參考個(gè)人項(xiàng)目 基于Spring Cloud、OAuth2.0開(kāi)發(fā)基于Vue前后分離的開(kāi)發(fā)平臺(tái)
QQ: 2270033969 一起來(lái)聊聊你們是咋用 spring cloud 的吧。
歡迎關(guān)注我們的公眾號(hào)獲得更多的好玩JavaEE 實(shí)踐
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/73932.html
摘要:以遠(yuǎn)程緩存服務(wù)器見(jiàn)長(zhǎng),對(duì)易揮發(fā)數(shù)據(jù)來(lái)說(shuō)是極快型數(shù)據(jù)庫(kù)。即使成功寫(xiě)入數(shù)據(jù)庫(kù),最后也可能會(huì)因?yàn)榫W(wǎng)絡(luò)故障而使得緩存服務(wù)器以失敗告終。 【編者按】本文作者為 Xinyu Liu,詳細(xì)介紹了 Redis 的特性,并輔之以豐富的用例。在本文的第一部分,將重點(diǎn)概述 Redis 的方方面面。文章系國(guó)內(nèi) ITOM 管理平臺(tái) OneAPM 編譯呈現(xiàn)。 建立在 Java 企業(yè)版之上的多層體系結(jié)構(gòu)是強(qiáng)大的服務(wù)...
摘要:完成狀態(tài)編寫(xiě)中已完成維護(hù)中原文是一個(gè)使用編寫(xiě)的開(kāi)源支持網(wǎng)絡(luò)基于內(nèi)存可選持久性的鍵值對(duì)存儲(chǔ)數(shù)據(jù)庫(kù)維基百科是目前業(yè)界使用廣泛的基于內(nèi)存的數(shù)據(jù)庫(kù)。 完成狀態(tài) [ ] 編寫(xiě)中 [ ] 已完成 [x] 維護(hù)中 原文 Redis Redis是一個(gè)使用ANSI C編寫(xiě)的開(kāi)源、支持網(wǎng)絡(luò)、基于內(nèi)存、可選持久性的鍵值對(duì)存儲(chǔ)數(shù)據(jù)庫(kù) ------ 維基百科 Redis 是目前業(yè)界使用廣泛的基于內(nèi)存的...
摘要:而且,用友云配置中心以服務(wù)的方式提供統(tǒng)一的管理界面,結(jié)合用友云的認(rèn)證中心可以提供可靠的安全保障。 微服務(wù)架構(gòu)是這幾年IT領(lǐng)域的一個(gè)高頻詞匯,越來(lái)越多的項(xiàng)目和應(yīng)用正在以微服務(wù)的思想進(jìn)行重構(gòu)。相比于單體應(yīng)用和SOA架構(gòu),微服務(wù)優(yōu)勢(shì)也逐漸凸顯,被廣大架構(gòu)師和技術(shù)人員引入和推崇。當(dāng)然,單體應(yīng)用、SOA、微服務(wù)等各有優(yōu)勢(shì)和不足。單體架構(gòu)在早期的企業(yè)內(nèi)部信息化或者搭建中小型項(xiàng)目時(shí)很常見(jiàn),簡(jiǎn)單說(shuō)就是...
摘要:第章附錄附錄通用的應(yīng)用程序?qū)傩钥梢栽谖募募蜃鳛槊钚虚_(kāi)關(guān),中指定各種屬性,本附錄提供了一個(gè)通用的屬性列表和對(duì)使用它們的底層類(lèi)的引用。本示例文件僅作為指南,不要將整個(gè)內(nèi)容復(fù)制粘貼到應(yīng)用程序中,相反,只選擇你需要的屬性。 第X章. 附錄 附錄A. 通用的應(yīng)用程序?qū)傩?可以在application.properties文件,application.yml文件,或作為命令行開(kāi)關(guān),中指定...
閱讀 3061·2021-10-27 14:16
閱讀 2878·2021-09-24 10:33
閱讀 2284·2021-09-23 11:21
閱讀 3228·2021-09-22 15:14
閱讀 811·2019-08-30 15:55
閱讀 1675·2019-08-30 15:53
閱讀 1741·2019-08-29 11:14
閱讀 2190·2019-08-28 18:11