首頁> Java> java教程> 主體

SpringBoot下整合快取工具類別CacheManager怎麼使用

王林
發布: 2023-05-12 19:10:13
轉載
1310 人瀏覽過

一.自訂工具類別定義

package com.demo.utils; import org.springframework.util.StringUtils; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; /** * Description: 缓存工具类 * 1.部分方法未验证,如有问题请自行修改 * 2.其他方法请自行添加 * * @Author: zhx & moon hongxu_1234@163.com * @Date: 2022-04-07 20:54 * @version: V1.0.0 */ public class Cache { /** * 屏蔽工具类的无参构造 避免工具类被实例化 */ private Cache(){} /** * 缓存留存期 30min 1H 24H */ public static final long CACHE_HOLD_TIME_30M = 30 * 60 * 1000L; public static final long CACHE_HOLD_TIME_1H = 2 * CACHE_HOLD_TIME_30M; public static final long CACHE_HOLD_TIME_24H = 24 * CACHE_HOLD_TIME_1H; public static final long CACHE_HOLD_TIME_FOREVER = -1L; /** * 缓存容量、最少使用容量 */ private static final int CACHE_MAX_CAP = 1000; private static final int CLEAN_LRU_CAP = 800; /** * 缓存当前大小 */ private static AtomicInteger CACHE_CURRENT_SIZE = new AtomicInteger(0); /** * 缓存对象 */ private static final Map CACHE_MAP = new ConcurrentHashMap<>(CACHE_MAX_CAP); /** * 最少使用记录 */ private static final List LRU_LIST = new LinkedList<>(); /** * 自动清理标志位 */ private static volatile boolean CLEAN_RUN_FLAG = false; /** * 默认30MIN * @param key * @param val */ public static void put(String key,Object val){ put(key,val,CACHE_HOLD_TIME_30M); } /** * 添加永久缓存 * @param key * @param val */ public static void putForever(String key,Object val){ put(key,val,CACHE_HOLD_TIME_FOREVER); } /** * 添加缓存 * @param key * @param val * @param ttlTime */ public static void put(String key,Object val,long ttlTime){ if (!StringUtils.hasLength(key) || null == val){ return; } checkSize(); updateCacheLru(key); CACHE_MAP.put(key,new Node(val,ttlTime)); } /** * 获取缓存信息 * @param key * @param clazz * @param  * @return */ public static  T get(String key,Class clazz){ if (!StringUtils.hasLength(key) || !CACHE_MAP.containsKey(key)){ return null; } updateCacheLru(key); return (T) CACHE_MAP.get(key).getVal(); } /** * 更新最近使用位置 * @param key */ private static void updateCacheLru(String key){ synchronized (LRU_LIST){ LRU_LIST.remove(key); LRU_LIST.add(0,key); } } /** * 删除,成功则容量-1 * @param key */ private static boolean remove(String key){ Node node = CACHE_MAP.remove(key); if (null!=node){ CACHE_CURRENT_SIZE.getAndDecrement(); return true; } return false; } /** * 检查是否超过容量,先清理过期,在清理最少使用 */ private static void checkSize(){ if (CACHE_CURRENT_SIZE.intValue() > CACHE_MAX_CAP){ deleteTimeOut(); } if (CACHE_CURRENT_SIZE.intValue() > CLEAN_LRU_CAP){ deleteLru(); } } /** * 删除最久未使用,尾部删除 * 永久缓存不会被清除 */ private static void deleteLru(){ synchronized (LRU_LIST){ while (LRU_LIST.size() > CLEAN_LRU_CAP){ int lastIndex = LRU_LIST.size() - 1; String key = LRU_LIST.get(lastIndex); if (!CACHE_MAP.get(key).isForever() && remove(key)){ LRU_LIST.remove(lastIndex); } } } } /** * 删除过期 */ private static void deleteTimeOut(){ List del = new LinkedList<>(); for (Map.Entry entry:CACHE_MAP.entrySet()){ if (entry.getValue().isExpired()){ del.add(entry.getKey()); } } for (String k:del){ remove(k); } } /** * 缓存是否已存在,过期则删除返回False * @param key * @return */ public static boolean contains(String key){ if (CACHE_MAP.containsKey(key)){ if (!CACHE_MAP.get(key).isExpired()){ return true; } if (remove(key)){ return false; } return true; } return false; } /** * 清空缓存 */ public static void clear(){ CACHE_MAP.clear(); CACHE_CURRENT_SIZE.set(0); LRU_LIST.clear(); } /** * 重置自动清理标志 * @param flag */ public static void setCleanRunFlag(boolean flag){ CLEAN_RUN_FLAG = flag; } /** * 自动清理过期缓存 */ private static void startAutoClean(){ if (!CLEAN_RUN_FLAG){ setCleanRunFlag(true); ScheduledExecutorService scheduledExecutor = new ScheduledThreadPoolExecutor(1); scheduledExecutor.scheduleAtFixedRate(()->{ try { Cache.setCleanRunFlag(true); while (CLEAN_RUN_FLAG){ Cache.deleteTimeOut(); } } catch (Exception e) { e.printStackTrace(); } },10,Cache.CACHE_HOLD_TIME_1H, TimeUnit.SECONDS); } } /** * 缓存对象类 */ public static class Node{ /** * 缓存值 */ private Object val; /** * 过期时间 */ private long ttlTime; public Node(Object val,long ttlTime){ this.val = val; if (ttlTime<0){ this.ttlTime = ttlTime; }else{ this.ttlTime = System.currentTimeMillis() + ttlTime; } } public Object getVal(){ return this.val; } public boolean isExpired(){ if (this.ttlTime<0){ return false; } return System.currentTimeMillis() > this.ttlTime; } public boolean isForever(){ if (this.ttlTime<0){ return true; } return false; } } }
登入後複製

二.SpringBoot 整合開源快取元件

1.開源快取元件

#分散式快取 分散式快取 分散式快取 本機快取 本機快取
#快取元件 類型
HAZELCAST #分散式快取
INFINISPAN
COUCHBASE
REDIS
CAFFEINE
CACHE2K


隨著硬體系統系統擴展和軟體升級,快取在應用中的地位和可應用性日漸提升,SpringBoot 為此設計了一套通用快取機制(規範)

此規範設計了兩個頂層介面Cache 和CacheManager 即快取和快取管理,透過實作CacheManager 引入快取元件,即可在SpringBoot專案內透過註解方便的設定快取

透過SpringBoot 的快取自動設定類,查看其可支援哪些快取元件的使用,部分原始碼如下:

//org.springframework.boot.autoconfigure.cache.CacheConfigurations static { Map mappings = new EnumMap<>(CacheType.class); mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class.getName()); mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class.getName()); mappings.put(CacheType.INFINISPAN, InfinispanCacheConfiguration.class.getName()); mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class.getName()); mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class.getName()); mappings.put(CacheType.REDIS, RedisCacheConfiguration.class.getName()); mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class.getName()); mappings.put(CacheType.CACHE2K, Cache2kCacheConfiguration.class.getName()); mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class.getName()); mappings.put(CacheType.NONE, NoOpCacheConfiguration.class.getName()); MAPPINGS = Collections.unmodifiableMap(mappings); }
登入後複製
2.快取註解 ##功能 @EenableCacheing 啟用註解式快取的功能,一般會加在專案啟動類別上
註解
##@Cacheable 如果存在緩存,則傳回快取資訊;不存在則取得值並新增至快取
@CachePut 新增緩存,可用於更新方法(強制將方法傳回值新增至指定Key )
@CacheEvict 刪除快取
#@Caching 包裝操作,將上面幾種註解打包在一起作用
@CacheConfig 通用配置註解,如果要對某個物件設定緩存,可以將此註解標註在類別上設定快取名稱、主鍵產生器等

3.快取測試(caffeine)

透過SpringBoot 整合Caffeine 進行快取註解演示,相關版本資訊參考依賴

1.Pom依賴
  4.0.0 org.example LenovoTest 1.0-SNAPSHOT  19 19 UTF-8 3.0.0    org.springframework.boot spring-boot-starter-web ${spring.version}   org.springframework.boot spring-boot-starter-logging     org.springframework.boot spring-boot-starter-log4j2 ${spring.version}   org.springframework.boot spring-boot-starter-aop ${spring.version}   org.springframework.boot spring-boot-starter-cache ${spring.version}   com.github.ben-manes.caffeine caffeine 3.1.2   org.projectlombok lombok 1.18.24   com.alibaba fastjson 2.0.14.graal   
登入後複製
2.Yml配置(指定快取實作類型)
server: port: 8088 spring: cache: type: caffeine custom-caffeine: specs: ## 用户信息写入10S后过期 userInfo: maximumSize=10,expireAfterWrite=10s ## 登陆信息写入5S后过期 accessInfo: maximumSize=10,expireAfterWrite=5s
登入後複製
3.專案啟動類別
package com.demo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCaching; /** * @author * @date * @since 1.8 */ @EnableCaching @SpringBootApplication public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class,args); } }
登入後複製
4.自訂快取設定

如果不透過Yml指定快取實作類型,則會使用預設實作

package com.demo.comfig; import com.github.benmanes.caffeine.cache.Caffeine; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cache.CacheManager; import org.springframework.cache.caffeine.CaffeineCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary; import java.util.HashMap; import java.util.Iterator; import java.util.Map; /** * @author * @date * @since 1.8 */ @Configuration public class CustomCaffeineConfig { /** * 加载 Caffeine 配置 * @return */ @Bean(name = "caffeineProperties") @ConfigurationProperties(prefix = "custom-caffeine.specs") public Map caffeineProperties(){ return new HashMap(16); } /** * 自定义 CacheManager * @param properties * @return */ @Bean @Primary public CacheManager caffeineManager(@Qualifier("caffeineProperties") Map properties){ CaffeineCacheManager manager = new CaffeineCacheManager(); Map.Entry entry; Iterator> iterator = properties.entrySet().iterator(); while (iterator.hasNext()){ entry = iterator.next(); manager.registerCustomCache(entry.getKey(), Caffeine.from(entry.getValue()).build()); } return manager; } }
登入後複製
5.測試類別

定義一個User 物件

package com.demo.entity; import lombok.Data; /** * @author zhanghx19 * @date 2023-01-28 15:53 * @since 1.8 */ @Data public class UserInfo { private String name; private String account; private long age; }
登入後複製

定義一個Controller 類用於測試

package com.demo.controller; import com.demo.entity.UserInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CachePut; import org.springframework.cache.annotation.Cacheable; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * @author * @date 2023-01-28 11:36 * @since 1.8 */ @RestController @RequestMapping("/test") public class TestController { /** * 注入缓存管理器,所有注解操作也可以直接操作管理器实现 */ @Autowired CacheManager cacheManager; /** * CachePut 强制刷新缓存 * @param id * @param val * @return */ @GetMapping("/update") @CachePut(cacheNames = "test" ,key = "#id") public String update(String id,String val){ //TODO Query Data By @{id} return val; } /** * Cacheable 查看缓存,存在则直接返回;否则查询数据,添加缓存并返回 * @param id * @param val * @return */ @GetMapping("/query") @Cacheable(cacheNames = "test" ,key = "#id" ) public String query(String id,String val){ //TODO Query Data By @{id} return val; } /** * 删除注解内指定的 缓存名下的 Key * @param id */ @GetMapping("/deleteTest") @CacheEvict(cacheNames = "test",key = "#id") public void deleteTest(String id){ } /** * 通过 cacheManager 删除缓存 * @param cacheNames * @param id */ @GetMapping("/deleteByNameAndKet") public void deleteByNameAndKet(String cacheNames,String id){ Cache cache = cacheManager.getCache(cacheNames); cache.evict(id); } /** * CachePut 强制缓存用户信息 且10秒后过期 * @param id * @param val * @return */ @GetMapping("/updateUser") @CachePut(cacheNames = "userInfo" ,key = "#id") public String updateUser(String id,String val){ return val; } /** * Cacheable 10秒内缓存不更新,丢失后可刷新为当前值 * @param id * @param val * @return */ @GetMapping("/queryUser") @Cacheable(cacheNames = "userInfo" ,key = "#id") public String queryUser(String id,String val){ return val; } /** * 缓存对象 * @param id * @param val * @return */ @GetMapping("/queryUserById") @Cacheable(cacheNames = "userInfo" ,key = "#id") public UserInfo getUserInfo(String id,String val){ UserInfo info = new UserInfo(); info.setAccount(id); info.setName(val); info.setAge(System.currentTimeMillis()); return info; } }
登入後複製
6.測試記錄

啟動項目,新增強制快取

SpringBoot下整合快取工具類別CacheManager怎麼使用

利用 Cacheable 嘗試刷新快取(返回已存在值)

SpringBoot下整合快取工具類別CacheManager怎麼使用

刪除快取

SpringBoot下整合快取工具類別CacheManager怎麼使用

#再利用Cacheable 嘗試重新整理快取(上面清除後則可重新整理)

SpringBoot下整合快取工具類別CacheManager怎麼使用

自動過期測試,透過CachePut 新增使用者資訊

SpringBoot下整合快取工具類別CacheManager怎麼使用

嘗試用Cacheable 刷新緩存,則10S 後可生效

SpringBoot下整合快取工具類別CacheManager怎麼使用

10 秒後

SpringBoot下整合快取工具類別CacheManager怎麼使用

#快取物件資訊

SpringBoot下整合快取工具類別CacheManager怎麼使用

以上是SpringBoot下整合快取工具類別CacheManager怎麼使用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:yisu.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!