最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot Caffeine+Redisson配置二級緩存實踐

 更新時間:2026年05月06日 09:01:09   作者:酒醉的胡鐵  
文章介紹了兩級緩存架構的必要性,詳細描述了使用Redission進行SpringBoot緩存整合的方法,包括配置本地緩存、設置過期時間、開啟緩存功能、解決key相同cacheNames不同的問題以及修改自定義緩存管理器等內容

問題說明

在高性能的服務架構設計中,緩存是一個不可或缺的環(huán)節(jié)。在實際的項目中,我們通常會將一些熱點數(shù)據(jù)存儲到Redis或MemCache這類緩存中間件中,只有當緩存的訪問沒有命中時再查詢數(shù)據(jù)庫。在提升訪問速度的同時,也能降低數(shù)據(jù)庫的壓力。

隨著不斷的發(fā)展,這一架構也產生了改進,在一些場景下可能單純使用Redis類的遠程緩存已經(jīng)不夠了,還需要進一步配合本地緩存使用,例如Guava cacheCaffeine,從而再次提升程序的響應速度與服務性能。于是,就產生了使用本地緩存作為一級緩存,再加上遠程緩存作為二級緩存的兩級緩存架構。

準備

集成Redission:SpringBoot 整合Redisson重寫cacheName支持多參數(shù)

<!--caffeine-->
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>

配置文件

增加本地緩存是為了解決高并發(fā)下頻繁查詢Redis的問題,配置了expireAfterWrite最后一次寫入或訪問后經(jīng)過固定時間過期為30秒,例如一次訪問一個頁面一直刷新,在30秒內無論怎么刷新都會走本地緩存,而且就算在29秒重新獲取了緩存,也會重新計算30秒

@EnableCaching開啟緩存功能,也可以加在啟動類上

package com.example.redisson.config;

import com.example.redisson.manager.PlusSpringCacheManager;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.TimeUnit;

/**
 * 緩存配置
 *
 * @author Lion Li
 */
@Configuration
@EnableCaching
public class CacheConfig {

    /**
     * caffeine 本地緩存處理器
     */
    @Bean
    public Cache<Object, Object> caffeine() {
        return Caffeine.newBuilder()
            // 設置最后一次寫入或訪問后經(jīng)過固定時間過期
            .expireAfterWrite(30, TimeUnit.SECONDS)
            // 初始的緩存空間大小
            .initialCapacity(100)
            // 緩存的最大條數(shù)
            .maximumSize(1000)
            .build();
    }

    /**
     * 自定義緩存管理器 整合spring-cache
     */
    @Bean
    public CacheManager cacheManager() {
        return new PlusSpringCacheManager();
    }

}

裝飾器

  • put方法是cache使用的也就是Redission ,會自動加上cacheNames
  • 而caffeine不使用cacheNames ,get方法的key是哪個就會緩存哪個key
  • 所以為了解決key相同,cacheNames 不同的問題增加了getUniqueKey方法 getName( ) = cacheNames

一個CacheNams對應一個Cache對象

package org.dromara.common.redis.manager;

import cn.hutool.core.lang.Console;
import org.dromara.common.core.utils.SpringUtils;
import org.springframework.cache.Cache;

import java.util.concurrent.Callable;

/**
 * Cache 裝飾器模式(用于擴展 Caffeine 一級緩存)
 *
 * @author LionLi
 */
public class CaffeineCacheDecorator implements Cache {

    private static final com.github.benmanes.caffeine.cache.Cache<Object, Object>
            CAFFEINE = SpringUtils.getBean("caffeine");

    private final Cache cache;

    public CaffeineCacheDecorator(Cache cache) {
        this.cache = cache;
    }

    @Override
    public String getName() {
        return cache.getName();
    }

    @Override
    public Object getNativeCache() {
        return cache.getNativeCache();
    }

    public String getUniqueKey(Object key) {
        return cache.getName() + ":" + key;
    }

    @Override
    public ValueWrapper get(Object key) {
        Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key));
        Console.log("redisson caffeine -> key: " + getUniqueKey(key) + ",value:" + o);
        return (ValueWrapper) o;
    }

    @SuppressWarnings("unchecked")
    public <T> T get(Object key, Class<T> type) {
        Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, type));
        Console.log("redisson caffeine -> key: " + getUniqueKey(key) + ",value:" + o);
        return (T) o;
    }

    @Override
    public void put(Object key, Object value) {
        cache.put(key, value);
    }

    public ValueWrapper putIfAbsent(Object key, Object value) {
        return cache.putIfAbsent(key, value);
    }

    @Override
    public void evict(Object key) {
        evictIfPresent(key);
    }

    public boolean evictIfPresent(Object key) {
        boolean b = cache.evictIfPresent(key);
        if (b) {
            CAFFEINE.invalidate(getUniqueKey(key));
        }
        return b;
    }

    @Override
    public void clear() {
        cache.clear();
    }

    public boolean invalidate() {
        return cache.invalidate();
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T> T get(Object key, Callable<T> valueLoader) {
        Object o = CAFFEINE.get(getUniqueKey(key), k -> cache.get(key, valueLoader));
        Console.log("redisson caffeine -> key: " + getUniqueKey(key) + ",value:" + o);
        return (T) o;
    }

}

修改自定義PlusSpringCacheManager,注入裝飾器

使用

@Cacheable(cacheNames = "demo:cache#60s#10m#20", key = "#key", condition = "#key != null")
@GetMapping("/test1")
public R<String> test1(String key, String value) {
    System.out.println("test1-->調用方法體");
    return R.ok("操作成功", value);
}

因為@Cacheable注解上來就會調用get方法,所以可以觸發(fā)本地緩存,@CachePut注解則不行

查看源碼可知,如果一級沒有獲取到,則獲取二級

緩存工具類

package com.example.redisson.utils;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.redisson.api.RMap;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;

import java.util.Set;

/**
 * 緩存操作工具類 {@link }
 *
 * @author Michelle.Chung
 * @date 2022/8/13
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings(value = {"unchecked"})
public class CacheUtils {

    private static final CacheManager CACHE_MANAGER = SpringUtils.getBean(CacheManager.class);

    /**
     * 獲取緩存組內所有的KEY
     *
     * @param cacheNames 緩存組名稱
     */
    public static Set<Object> keys(String cacheNames) {
        RMap<Object, Object> rmap = (RMap<Object, Object>) CACHE_MANAGER.getCache(cacheNames).getNativeCache();
        return rmap.keySet();
    }

    /**
     * 獲取緩存值
     *
     * @param cacheNames 緩存組名稱
     * @param key        緩存key
     */
    public static <T> T get(String cacheNames, Object key) {
        Cache.ValueWrapper wrapper = CACHE_MANAGER.getCache(cacheNames).get(key);
        return wrapper != null ? (T) wrapper.get() : null;
    }

    /**
     * 保存緩存值
     *
     * @param cacheNames 緩存組名稱
     * @param key        緩存key
     * @param value      緩存值
     */
    public static void put(String cacheNames, Object key, Object value) {
        CACHE_MANAGER.getCache(cacheNames).put(key, value);
    }

    /**
     * 刪除緩存值
     *
     * @param cacheNames 緩存組名稱
     * @param key        緩存key
     */
    public static void evict(String cacheNames, Object key) {
        CACHE_MANAGER.getCache(cacheNames).evict(key);
    }

    /**
     * 清空緩存值
     *
     * @param cacheNames 緩存組名稱
     */
    public static void clear(String cacheNames) {
        CACHE_MANAGER.getCache(cacheNames).clear();
    }

}

總結

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • 一文帶你掌握Java?SPI的原理和實踐

    一文帶你掌握Java?SPI的原理和實踐

    在Java中,我們經(jīng)常會提到面向接口編程,這樣減少了模塊之間的耦合,更加靈活,Java?SPI?(Service?Provider?Interface)就提供了這樣的機制,本文就來講講它的原理與具體使用吧
    2023-05-05
  • spring mvc 實現(xiàn)獲取后端傳遞的值操作示例

    spring mvc 實現(xiàn)獲取后端傳遞的值操作示例

    這篇文章主要介紹了spring mvc 實現(xiàn)獲取后端傳遞的值操作,結合實例形式詳細分析了spring mvc使用JSTL 方法獲取后端傳遞的值相關操作技巧
    2019-11-11
  • Java并發(fā)編程Callable與Future的應用實例代碼

    Java并發(fā)編程Callable與Future的應用實例代碼

    這篇文章主要介紹了Java并發(fā)編程Callable與Future的應用實例代碼,具有一定借鑒價值,需要的朋友可以參考下
    2018-01-01
  • SpringBoot動態(tài)修改yml配置文件的方法詳解

    SpringBoot動態(tài)修改yml配置文件的方法詳解

    這篇文章主要為大家詳細介紹了SpringBoot動態(tài)修改yml配置文件的方法,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • mybatis配置獲取自增主鍵的操作方法

    mybatis配置獲取自增主鍵的操作方法

    當需要剛剛插入數(shù)據(jù)庫的數(shù)據(jù)對應的新增主鍵時,通過配置xml文件,使數(shù)據(jù)庫返回新增主鍵id,并把主鍵id與類參數(shù)對應,本文給大家介紹了mybatis配置獲取自增主鍵的操作方法,需要的朋友可以參考下
    2024-05-05
  • java實現(xiàn)九宮格拼圖游戲

    java實現(xiàn)九宮格拼圖游戲

    這篇文章主要為大家詳細介紹了java實現(xiàn)九宮格拼圖游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Java中的XML解析技術詳析

    Java中的XML解析技術詳析

    XML文檔是一個文檔樹,從根部開始,并擴展到樹的最底部,下面這篇文章主要給大家介紹了關于Java中XML解析技術的相關資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-08-08
  • java實現(xiàn)支付寶退款功能

    java實現(xiàn)支付寶退款功能

    這篇文章主要為大家詳細 介紹了java實現(xiàn)支付寶退款功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • Java實題演練二叉搜索樹與雙向鏈表分析

    Java實題演練二叉搜索樹與雙向鏈表分析

    這篇文章主要介紹了Java二叉搜索樹與雙向鏈表,總的來說這并不是一道難題,那為什么要拿出這道題介紹?拿出這道題真正想要傳達的是解題的思路,以及不斷優(yōu)化探尋最優(yōu)解的過程。希望通過這道題能給你帶來一種解題優(yōu)化的思路
    2022-12-12
  • springcloud中Feign超時提示Read timed out executing POST的問題及解決方法

    springcloud中Feign超時提示Read timed out executing

    Feign接口調用分兩層,Ribbon的調用和Hystrix調用,理論上設置Ribbon的時間即可,但是Ribbon的超時時間和Hystrix的超時時間需要結合起來,這篇文章給大家介紹springcloud之Feign超時提示Read timed out executing POST問題及解決方法,感興趣的朋友一起看看吧
    2024-01-01

最新評論

西贡区| 金寨县| 青岛市| 云安县| 正阳县| 鄱阳县| 唐河县| 武义县| 林甸县| 巴东县| 临沂市| 巴林右旗| 松溪县| 额济纳旗| 佛教| 泸定县| 平顶山市| 禹城市| 五常市| 榕江县| 清流县| 赤城县| 常德市| 垦利县| 搜索| 宁明县| 绿春县| 静安区| 韩城市| 锡林郭勒盟| 绥德县| 平远县| 莱芜市| 铜川市| 岳阳市| 景谷| 井冈山市| 疏附县| 永兴县| 合阳县| 伊宁县|