失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > SpringBoot 下集成缓存工具类 CacheManager

SpringBoot 下集成缓存工具类 CacheManager

时间:2021-11-21 19:01:24

相关推荐

SpringBoot 下集成缓存工具类 CacheManager

Java 缓存工具类 Cache

一.自定义工具类定义二.SpringBoot 集成开源缓存组件1.开源缓存组件2.缓存注解3.缓存测试(caffeine)1.Pom依赖2.Yml配置(指定缓存实现类型)3.项目启动类4.自定义缓存配置5.测试类6.测试记录

一.自定义工具类定义

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@* @Date: -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<String,Node> CACHE_MAP = new ConcurrentHashMap<>(CACHE_MAX_CAP);/*** 最少使用记录*/private static final List<String> 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 <T>* @return*/public static <T> T get(String key,Class<T> 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<String> del = new LinkedList<>();for (Map.Entry<String,Node> 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.开源缓存组件

随着硬件系统系统扩展和软件升级,缓存在应用中的地位和可应用性日渐提升,SpringBoot 为此设计了一套通用缓存机制(规范)

此规范设计了两个顶层接口 Cache 和 CacheManager 即缓存和缓存管理,通过实现CacheManager 引入缓存组件,即可在SpringBoot项目内通过注解方便的设置缓存

通过 SpringBoot 的缓存自动配置类,查看其可支持哪些缓存组件的使用,部分源码如下:

//org.springframework.boot.autoconfigure.cache.CacheConfigurationsstatic {Map<CacheType, String> 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.缓存注解

3.缓存测试(caffeine)

通过 SpringBoot 集成 Caffeine 进行缓存注解演示,相关版本信息参考依赖

1.Pom依赖

<?xml version="1.0" encoding="UTF-8"?><project xmlns="/POM/4.0.0"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.example</groupId><artifactId>LenovoTest</artifactId><version>1.0-SNAPSHOT</version><properties><piler.source>19</piler.source><piler.target>19</piler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring.version>3.0.0</spring.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>${spring.version}</version><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-logging</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j2</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId><version>${spring.version}</version></dependency><dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>3.1.2</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.14.graal</version></dependency></dependencies></project>

2.Yml配置(指定缓存实现类型)

server:port: 8088spring:cache:type: caffeinecustom-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@SpringBootApplicationpublic class TestApplication {public static void main(String[] args) {SpringApplication.run(TestApplication.class,args);}}

4.自定义缓存配置

如果不通过Yml指定缓存实现类型,则将使用默认实现

package fig;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*/@Configurationpublic class CustomCaffeineConfig {/*** 加载 Caffeine 配置* @return*/@Bean(name = "caffeineProperties")@ConfigurationProperties(prefix = "custom-caffeine.specs")public Map<String,String> caffeineProperties(){return new HashMap(16);}/*** 自定义 CacheManager* @param properties* @return*/@Bean@Primarypublic CacheManager caffeineManager(@Qualifier("caffeineProperties") Map<String,String> properties){CaffeineCacheManager manager = new CaffeineCacheManager();Map.Entry<String,String> entry;Iterator<Map.Entry<String,String>> 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 -01-28 15:53* @since 1.8*/@Datapublic 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 -01-28 11:36* @since 1.8*/@RestController@RequestMapping("/test")public class TestController {/*** 注入缓存管理器,所有注解操作也可以直接操作管理器实现*/@AutowiredCacheManager 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.测试记录

启动项目,添加强制缓存

利用 Cacheable 尝试刷新缓存(返回已存在值)

删除缓存

再次利用 Cacheable 尝试刷新缓存(上面清除后则可刷新)

自动过期测试,通过 CachePut 添加用户信息

尝试用 Cacheable 刷新缓存,则 10S 后可生效

10 秒后

缓存对象信息

如果觉得《SpringBoot 下集成缓存工具类 CacheManager》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。