摘要:在多租戶下租戶所請求的并不是同一入?yún)㈦m然看起來參數(shù)名參數(shù)值都是一樣的,更不能返回同一個結果。默認的根據(jù)入?yún)韰^(qū)分不能滿足多租戶系統(tǒng)的設計需求不能實現(xiàn)根據(jù)租戶隔離。
spring cache 的概念
Spring 支持基于注釋(annotation)的緩存(cache)技術,它本質(zhì)上不是一個具體的緩存實現(xiàn)方案(例如 EHCache 或者 OSCache),而是一個對緩存使用的抽象,通過在既有代碼中添加少量它定義的各種 annotation,即能夠達到緩存方法的返回對象的效果。
@Cacheable 使用效果 ,更具 cacheName(value) + 請求入?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); } }}多租戶下緩存問題分析
默認情況 A租戶入?yún)镵1 請求 應用,spring cache 會自動緩存 K1 的值,如果B租戶 入?yún)⑼瑫r為K1 請求應用時,spring cache 還是會自動關聯(lián)到同一個 Redis K1 上邊查詢數(shù)據(jù)。
在多租戶下 A/B 租戶所請求的K1 并不是同一入?yún)ⅲm然看起來參數(shù)名 參數(shù)值都是一樣的),更不能返回同一個結果。
默認的spring cache 根據(jù)入?yún)韰^(qū)分 不能滿足多租戶系統(tǒng)的設計需求,不能實現(xiàn)根據(jù)租戶隔離。
區(qū)分緩存增加租戶標識A租戶入?yún)镵1 ,spring cache 維護Redis Key 在拼接一個租戶信息
KEY = cacheName + 入?yún)?+ 租戶標識
這樣A/B 租戶請求參數(shù)相同時,讀取的也是不同的Key 里面的值,避免數(shù)據(jù)臟讀,保證隔離型
重寫Spring Cache 的 cacheManager 緩存管理器
從上下文中獲取租戶ID,重寫@Cacheable value 值即可完成,然后注入這個 cacheManager
@Slf4j public class RedisAutoCacheManager extends RedisCacheManager { /** * 從上下文中獲取租戶ID,重寫@Cacheable value 值 * @param name * @return */ @Override public Cache getCache(String name) { return super.getCache(TenantContextHolder.getTenantId() + StrUtil.COLON + name); } }
為什么要用 StrUtil.COLON 即 ":" 分割
在GUI 工具中,會通過":"的分隔符,進行分組,展示效果會更好
增加 spring cache 的主動過期功能默認的注解里面沒有關于時間的入?yún)?,如下圖
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" 通過對vaue 追加一個數(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); } }
重寫cachemanager 另個重要的方法 創(chuàng)建緩存的方法,通過截取 value 中設置的過期時間,賦值給你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 操作緩存時 獲取到上步設置的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()); }總結
通過對spring cache 的擴展即可實現(xiàn)對緩存 一些透明操作
cachemanager 是springcache 對外提供的API 擴展入口
以上源碼參考個人項目 基于Spring Cloud、OAuth2.0開發(fā)基于Vue前后分離的開發(fā)平臺
QQ: 2270033969 一起來聊聊你們是咋用 spring cloud 的吧。
歡迎關注我們的公眾號獲得更多的好玩JavaEE 實踐
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://www.ezyhdfw.cn/yun/73932.html
摘要:以遠程緩存服務器見長,對易揮發(fā)數(shù)據(jù)來說是極快型數(shù)據(jù)庫。即使成功寫入數(shù)據(jù)庫,最后也可能會因為網(wǎng)絡故障而使得緩存服務器以失敗告終。 【編者按】本文作者為 Xinyu Liu,詳細介紹了 Redis 的特性,并輔之以豐富的用例。在本文的第一部分,將重點概述 Redis 的方方面面。文章系國內(nèi) ITOM 管理平臺 OneAPM 編譯呈現(xiàn)。 建立在 Java 企業(yè)版之上的多層體系結構是強大的服務...
摘要:完成狀態(tài)編寫中已完成維護中原文是一個使用編寫的開源支持網(wǎng)絡基于內(nèi)存可選持久性的鍵值對存儲數(shù)據(jù)庫維基百科是目前業(yè)界使用廣泛的基于內(nèi)存的數(shù)據(jù)庫。 完成狀態(tài) [ ] 編寫中 [ ] 已完成 [x] 維護中 原文 Redis Redis是一個使用ANSI C編寫的開源、支持網(wǎng)絡、基于內(nèi)存、可選持久性的鍵值對存儲數(shù)據(jù)庫 ------ 維基百科 Redis 是目前業(yè)界使用廣泛的基于內(nèi)存的...
摘要:而且,用友云配置中心以服務的方式提供統(tǒng)一的管理界面,結合用友云的認證中心可以提供可靠的安全保障。 微服務架構是這幾年IT領域的一個高頻詞匯,越來越多的項目和應用正在以微服務的思想進行重構。相比于單體應用和SOA架構,微服務優(yōu)勢也逐漸凸顯,被廣大架構師和技術人員引入和推崇。當然,單體應用、SOA、微服務等各有優(yōu)勢和不足。單體架構在早期的企業(yè)內(nèi)部信息化或者搭建中小型項目時很常見,簡單說就是...
摘要:第章附錄附錄通用的應用程序?qū)傩钥梢栽谖募?,文件,或作為命令行開關,中指定各種屬性,本附錄提供了一個通用的屬性列表和對使用它們的底層類的引用。本示例文件僅作為指南,不要將整個內(nèi)容復制粘貼到應用程序中,相反,只選擇你需要的屬性。 第X章. 附錄 附錄A. 通用的應用程序?qū)傩?可以在application.properties文件,application.yml文件,或作為命令行開關,中指定...
閱讀 3147·2021-10-27 14:16
閱讀 2956·2021-09-24 10:33
閱讀 2365·2021-09-23 11:21
閱讀 3284·2021-09-22 15:14
閱讀 888·2019-08-30 15:55
閱讀 1749·2019-08-30 15:53
閱讀 1855·2019-08-29 11:14
閱讀 2245·2019-08-28 18:11