0

0

SpringBoot下集成缓存工具类CacheManager怎么使用

王林

王林

发布时间:2023-05-12 19:10:13

|

2010人浏览过

|

来源于亿速云

转载

一.自定义工具类定义

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怎么使用

Frase
Frase

Frase是一款出色的长篇 AI 写作工具,快速创建seo优化的内容。

下载

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

SpringBoot下集成缓存工具类CacheManager怎么使用

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

SpringBoot下集成缓存工具类CacheManager怎么使用

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

SpringBoot下集成缓存工具类CacheManager怎么使用

10 秒后

SpringBoot下集成缓存工具类CacheManager怎么使用

缓存对象信息

SpringBoot下集成缓存工具类CacheManager怎么使用

相关专题

更多
Java JVM 原理与性能调优实战
Java JVM 原理与性能调优实战

本专题系统讲解 Java 虚拟机(JVM)的核心工作原理与性能调优方法,包括 JVM 内存结构、对象创建与回收流程、垃圾回收器(Serial、CMS、G1、ZGC)对比分析、常见内存泄漏与性能瓶颈排查,以及 JVM 参数调优与监控工具(jstat、jmap、jvisualvm)的实战使用。通过真实案例,帮助学习者掌握 Java 应用在生产环境中的性能分析与优化能力。

3

2026.01.20

PS使用蒙版相关教程
PS使用蒙版相关教程

本专题整合了ps使用蒙版相关教程,阅读专题下面的文章了解更多详细内容。

55

2026.01.19

java用途介绍
java用途介绍

本专题整合了java用途功能相关介绍,阅读专题下面的文章了解更多详细内容。

67

2026.01.19

java输出数组相关教程
java输出数组相关教程

本专题整合了java输出数组相关教程,阅读专题下面的文章了解更多详细内容。

36

2026.01.19

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

10

2026.01.19

xml格式相关教程
xml格式相关教程

本专题整合了xml格式相关教程汇总,阅读专题下面的文章了解更多详细内容。

11

2026.01.19

PHP WebSocket 实时通信开发
PHP WebSocket 实时通信开发

本专题系统讲解 PHP 在实时通信与长连接场景中的应用实践,涵盖 WebSocket 协议原理、服务端连接管理、消息推送机制、心跳检测、断线重连以及与前端的实时交互实现。通过聊天系统、实时通知等案例,帮助开发者掌握 使用 PHP 构建实时通信与推送服务的完整开发流程,适用于即时消息与高互动性应用场景。

15

2026.01.19

微信聊天记录删除恢复导出教程汇总
微信聊天记录删除恢复导出教程汇总

本专题整合了微信聊天记录相关教程大全,阅读专题下面的文章了解更多详细内容。

152

2026.01.18

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

139

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Redis6入门到精通超详细教程
Redis6入门到精通超详细教程

共47课时 | 5.3万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号