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

SpringBoot應(yīng)用中的多層緩存實(shí)踐

 更新時間:2026年02月26日 10:21:30   作者:程序員wayn  
在本文中,我們將深入探討SpringBoot應(yīng)用中多層緩存的實(shí)現(xiàn)思路,通過本地Caffeine緩存(L1)和遠(yuǎn)程Redis緩存(L2)的組合,減少與遠(yuǎn)程服務(wù)的通信次數(shù),提升應(yīng)用性能,感興趣的可以了解一下

在本文中,我們將深入探討 Spring Boot 應(yīng)用中多層緩存的實(shí)現(xiàn)思路。具體而言,我們會采用本地一級緩存(L1)遠(yuǎn)程分布式二級緩存(L2) 的組合方案:其中一級緩存使用較短的過期時間,二級緩存則配置較長的過期時間。

多層緩存的核心邏輯是優(yōu)先查詢本地緩存,若本地緩存未命中,則再查詢二級緩存。其核心目標(biāo)是通過減少與遠(yuǎn)程服務(wù)的往返通信次數(shù),顯著提升應(yīng)用性能。

技術(shù)選型說明

  • 一級緩存(L1) :采用 Caffeine 緩存庫實(shí)現(xiàn)。Caffeine 是當(dāng)前性能最優(yōu)的本地緩存方案之一,基于 W-TinyLFU 淘汰算法(高命中率),支持高效的內(nèi)存管理、靈活的過期策略(寫入后過期、訪問后過期等),且對 Java 8+ 特性適配良好。
  • 二級緩存(L2) :采用 Redis 實(shí)現(xiàn)。Redis 作為主流的分布式內(nèi)存數(shù)據(jù)存儲,具備高可用、高并發(fā)支持能力,適合作為跨服務(wù)共享的二級緩存。

需要說明的是,本文的實(shí)現(xiàn)方案具備通用性——只需輕微調(diào)整,即可適配 Ehcache、Hazelcast 等其他緩存組件。

一、Caffeine 依賴引入

要在 Spring Boot 項(xiàng)目中使用 Caffeine,需先引入對應(yīng)的依賴。推薦通過 Spring Boot 官方的依賴管理(spring-boot-dependencies)控制版本,避免版本沖突;若未使用 Spring Boot 父工程,則需手動指定 Caffeine 版本。

Maven 項(xiàng)目依賴

pom.xml 中添加以下依賴:

<!-- 方式1:直接引入 Caffeine 核心依賴(推薦,版本由 Spring Boot 父工程管理) -->
<dependency>
    <groupId>com.github.ben-manes.caffeine</groupId>
    <artifactId>caffeine</artifactId>
</dependency>

<!-- 方式2:若需使用 Spring 對 Caffeine 的緩存適配(如 CaffeineCacheManager),可引入 spring-boot-starter-cache -->
<!-- 注:spring-boot-starter-cache 已間接包含 Caffeine 依賴(需確保項(xiàng)目已啟用緩存抽象) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

Caffeine 優(yōu)勢

選擇 Caffeine 作為一級緩存,核心原因在于其卓越的性能與靈活性:

  • 高命中率:采用 W-TinyLFU(Window Tiny Least Frequently Used)淘汰算法,在高并發(fā)場景下比傳統(tǒng) LRU 算法命中率提升 10%-20%。
  • 低延遲:底層基于 Java 并發(fā)容器(如 ConcurrentHashMap),讀寫操作均為低延遲設(shè)計(jì),支持每秒數(shù)百萬次緩存訪問。
  • 靈活的過期策略:支持 expireAfterWrite(寫入后過期)、expireAfterAccess(訪問后過期)、expireAfter(自定義過期邏輯),滿足不同業(yè)務(wù)場景。
  • 內(nèi)存安全:支持配置最大緩存容量(maximumSize),當(dāng)緩存達(dá)到閾值時自動淘汰舊數(shù)據(jù),避免內(nèi)存溢出。

二、簡單卻粗糙的雙層緩存實(shí)現(xiàn)方案

在 Spring Boot 中,我們通常使用 @Cacheable 注解實(shí)現(xiàn)方法結(jié)果緩存。若要實(shí)現(xiàn)雙層緩存,最直接的思路是:手動檢查一級緩存(Caffeine),未命中時再查詢二級緩存(Redis)。

首先看二級緩存服務(wù)的實(shí)現(xiàn)(基于 @Cacheable 注解):

public class L2CacheService {

    @Cacheable(value = "myCache", key = "#id")
    public String getFromCache(String id) {
        // 該方法的返回結(jié)果會被自動緩存(默認(rèn)對接二級緩存)
        return "Hello " + id;
    }
}

在此基礎(chǔ)上,封裝一級緩存邏輯,形成雙層緩存調(diào)用:

public class L1CacheService {

    @Autowired
    private L2CacheService l2CacheService;

    // 初始化 Caffeine 本地緩存:最大緩存數(shù) 100,寫入后 10 分鐘過期
    private Cache<String, String> caffeineCache = Caffeine.newBuilder()
        .maximumSize(100)
        .expireAfterWrite(10, TimeUnit.MINUTES)
        .build();

    public String getFromCache(String id) {
        // 1. 優(yōu)先查詢一級緩存
        String result = caffeineCache.getIfPresent(id);
        if (result == null) {
            // 2. 一級緩存未命中,查詢二級緩存
            result = l2CacheService.getFromCache(id);
            // 3. 若二級緩存命中,同步到一級緩存
            if (result != null) {
                caffeineCache.put(id, result);
            }
        }
        return result;
    }
}

顯然,這種方案并不理想:代碼冗余度高,且需為每個緩存場景單獨(dú)創(chuàng)建服務(wù)類,極易因手動維護(hù)緩存邏輯導(dǎo)致錯誤(如緩存同步遺漏、過期時間不一致等)。我們有更優(yōu)的實(shí)現(xiàn)方式。

三、基于 Spring 緩存抽象的優(yōu)化方案

Spring 提供的 CompositeCacheManager(組合緩存管理器)可將多個緩存組件整合,大幅簡化雙層緩存的配置邏輯。以下是具體實(shí)現(xiàn):

1. 緩存配置類

@Configuration
@EnableCaching // 啟用 Spring 緩存抽象
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        // 1. 配置一級緩存(Caffeine)
        CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager("myCache");
        caffeineCacheManager.setCaffeine(caffeineCacheBuilder());
        caffeineCacheManager.setAllowNullValues(false); // 不允許緩存 null 值

        // 2. 配置二級緩存(Redis)
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate());
        redisCacheManager.setUsePrefix(true); // 啟用緩存鍵前綴,避免鍵沖突

        // 3. 組合緩存管理器:優(yōu)先使用 Caffeine 緩存,未命中則查詢 Redis
        CompositeCacheManager compositeCacheManager = new CompositeCacheManager(caffeineCacheManager, redisCacheManager);
        compositeCacheManager.setFallbackToNoOpCache(true); // 當(dāng)緩存不存在時,啟用無操作緩存降級(避免報(bào)錯)

        return compositeCacheManager;
    }

    // 配置 Caffeine 緩存策略
    private Caffeine<Object, Object> caffeineCacheBuilder() {
        return Caffeine.newBuilder()
            .maximumSize(100) // 最大緩存條目數(shù)
            .expireAfterWrite(10, TimeUnit.MINUTES); // 寫入后 10 分鐘過期
    }

    // 配置 Redis 模板(序列化方式)
    @Bean
    public RedisTemplate<String, String> redisTemplate() {
        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        // 配置鍵/值的序列化器(避免 Redis 中存儲亂碼)
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        return redisTemplate;
    }

    // 配置 Redis 連接工廠(默認(rèn)使用 Lettuce 客戶端)
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory();
    }
}

2. 業(yè)務(wù)服務(wù)實(shí)現(xiàn)

只需在方法上添加 @Cacheable 注解,即可自動觸發(fā)雙層緩存邏輯:

@Cacheable(value = "myCache", key = "#id")
public String getFromCache(String id) {
    return "Hello " + id;
}

方案優(yōu)勢與局限性

  • 優(yōu)勢:基于 Spring 原生緩存抽象,無需手動維護(hù)緩存調(diào)用邏輯,代碼簡潔且容錯性強(qiáng)。
  • 局限性CompositeCacheManager 僅支持“一級緩存未命中則查詢二級緩存”,但不會將二級緩存的命中結(jié)果同步到一級緩存。若需實(shí)現(xiàn)緩存同步,仍需在業(yè)務(wù)方法中手動編寫邏輯:
public String getFromCache(String id) {
    // 1. 查詢一級緩存
    String result = caffeineCacheManager.getCache("myCache").get(id, String.class);
    if (result == null) {
        // 2. 一級緩存未命中,查詢二級緩存
        result = redisCacheManager.getCache("myCache").get(id, String.class);
        // 3. 同步二級緩存結(jié)果到一級緩存
        if (result != null) {
            caffeineCacheManager.getCache("myCache").put(id, result);
        }
    }
    return result;
}

顯然,這種“配置+手動代碼”的混合模式仍不完美。接下來,我們將通過自定義緩存管理器,實(shí)現(xiàn)真正無縫的雙層緩存同步。

四、基于自定義 CacheManager 的完美方案

通過實(shí)現(xiàn) Spring 的 CacheManager 接口與 Cache 接口,我們可以完全掌控雙層緩存的讀寫、同步與過期邏輯,實(shí)現(xiàn)“一次注解,雙向同步”。

1. 自定義緩存管理器(CustomCacheManager)

import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import java.util.Collection;

public class CustomCacheManager implements CacheManager {

    // 依賴注入一級緩存管理器(Caffeine)與二級緩存管理器(Redis)
    private final CacheManager caffeineCacheManager;
    private final CacheManager redisCacheManager;

    public CustomCacheManager(CacheManager caffeineCacheManager, CacheManager redisCacheManager) {
        this.caffeineCacheManager = caffeineCacheManager;
        this.redisCacheManager = redisCacheManager;
    }

    // 獲取緩存實(shí)例:返回自定義的雙層緩存實(shí)現(xiàn)
    @Override
    public Cache getCache(String name) {
        Cache caffeineCache = caffeineCacheManager.getCache(name);
        Cache redisCache = redisCacheManager.getCache(name);
        return new CustomCache(caffeineCache, redisCache);
    }

    // 獲取所有緩存名稱(與一級緩存保持一致)
    @Override
    public Collection<String> getCacheNames() {
        return caffeineCacheManager.getCacheNames();
    }
}

2. 自定義緩存實(shí)現(xiàn)(CustomCache)

import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import java.util.concurrent.Callable;

// 采用 record 類型簡化代碼(JDK 16+ 支持),也可使用 class 實(shí)現(xiàn)
public record CustomCache(Cache firstLevelCache, Cache secondLevelCache) implements Cache {

    // 緩存名稱:與一級緩存保持一致
    @Override
    public String getName() {
        return firstLevelCache.getName();
    }

    // 原生緩存實(shí)例:返回一級緩存的原生實(shí)例
    @Override
    public Object getNativeCache() {
        return firstLevelCache.getNativeCache();
    }

    // 緩存查詢:優(yōu)先查一級,未命中則查二級,并同步到一級
    @Override
    public ValueWrapper get(Object key) {
        // 1. 查詢一級緩存
        ValueWrapper valueWrapper = firstLevelCache.get(key);
        if (valueWrapper == null) {
            // 2. 一級未命中,查詢二級緩存
            valueWrapper = secondLevelCache.get(key);
            if (valueWrapper != null) {
                // 3. 同步二級緩存結(jié)果到一級
                firstLevelCache.put(key, valueWrapper.get());
            }
        }
        return valueWrapper;
    }

    // 帶類型的緩存查詢:邏輯與 get(Object key) 一致
    @Override
    public <T> T get(Object key, Class<T> type) {
        T value = firstLevelCache.get(key, type);
        if (value == null) {
            value = secondLevelCache.get(key, type);
            if (value != null) {
                firstLevelCache.put(key, value);
            }
        }
        return value;
    }

    // 帶值加載器的查詢:優(yōu)先從一級緩存加載,失敗則從二級加載
    @Override
    public <T> T get(Object key, Callable<T> valueLoader) {
        try {
            // 優(yōu)先從一級緩存加載
            return firstLevelCache.get(key, valueLoader);
        } catch (Exception e) {
            // 一級緩存加載失?。ㄈ鐭o數(shù)據(jù)),從二級緩存加載
            return secondLevelCache.get(key, valueLoader);
        }
    }

    // 緩存寫入:同時寫入一級與二級緩存
    @Override
    public void put(Object key, Object value) {
        firstLevelCache.put(key, value);
        secondLevelCache.put(key, value);
    }

    // 緩存刪除:同時刪除一級與二級緩存的對應(yīng)鍵
    @Override
    public void evict(Object key) {
        firstLevelCache.evict(key);
        secondLevelCache.evict(key);
    }

    // 緩存清空:同時清空一級與二級緩存
    @Override
    public void clear() {
        firstLevelCache.clear();
        secondLevelCache.clear();
    }
}

3. 配置自定義緩存管理器

@Configuration
@EnableCaching
public class CacheConfig {

    public static final String CACHE_NAME = "doubleCachingCache";

    // 配置自定義緩存管理器
    @Bean
    public CacheManager customCacheManager(RedisConnectionFactory redisConnectionFactory) {
        // 1. 配置一級緩存(Caffeine)
        CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
        caffeineCacheManager.setCaffeine(
                Caffeine.newBuilder()
                        .maximumSize(100) // 一級緩存最大條目數(shù)
                        .expireAfterWrite(Duration.ofMinutes(10)) // 一級緩存過期時間:10 分鐘
        );

        // 2. 配置二級緩存(Redis)
        RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(
                        RedisCacheConfiguration.defaultCacheConfig()
                                .entryTtl(Duration.ofHours(1)) // 二級緩存過期時間:1 小時
                )
                .build();

        // 3. 返回自定義緩存管理器(整合一級與二級緩存)
        return new CustomCacheManager(caffeineCacheManager, redisCacheManager);
    }
}

4. 業(yè)務(wù)服務(wù)使用

無需任何額外代碼,僅通過 @Cacheable 注解即可觸發(fā)完整的雙層緩存邏輯:

@Cacheable(value = CacheConfig.CACHE_NAME, key = "#id")
public String getFromCache(String id) {
    return "Hello " + id;
}

核心邏輯說明

  • 查詢邏輯:一級緩存命中 → 直接返回;一級未命中 → 查詢二級緩存 → 同步到一級緩存后返回。
  • 寫入邏輯:數(shù)據(jù)同時寫入一級與二級緩存,確保緩存一致性。
  • 刪除/清空邏輯:操作同時作用于兩級緩存,避免“一級緩存已刪、二級緩存仍存在”的臟數(shù)據(jù)問題。

五、總結(jié)

本文詳細(xì)介紹了 Spring Boot 應(yīng)用中以 Caffeine 為本地一級緩存、Redis 為分布式二級緩存的多層緩存實(shí)現(xiàn),從手動管理的粗糙方案、Spring CompositeCacheManager 的優(yōu)化方案,到自定義 CacheManager 實(shí)現(xiàn)緩存自動同步的完美方案,并搭配 TestContainers 測試驗(yàn)證,為提升應(yīng)用性能、保證緩存一致性提供了可落地的實(shí)踐指南。

到此這篇關(guān)于SpringBoot應(yīng)用中的多層緩存實(shí)踐的文章就介紹到這了,更多相關(guān)SpringBoot 多層緩存內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot使用Redisson實(shí)現(xiàn)分布式鎖(秒殺系統(tǒng))

    SpringBoot使用Redisson實(shí)現(xiàn)分布式鎖(秒殺系統(tǒng))

    這篇文章主要為大家詳細(xì)介紹了SpringBoot使用Redisson實(shí)現(xiàn)分布式鎖,秒殺系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • springboot全局配置文件與多環(huán)境配置的全過程

    springboot全局配置文件與多環(huán)境配置的全過程

    SpringBoot項(xiàng)目在多環(huán)境配置上表現(xiàn)的非常優(yōu)秀,只需要非常簡單的操作就可以完成配置,下面這篇文章主要給大家介紹了關(guān)于springboot全局配置文件與多環(huán)境配置的相關(guān)資料,需要的朋友可以參考下
    2021-12-12
  • ireport數(shù)據(jù)表格報(bào)表的簡單使用

    ireport數(shù)據(jù)表格報(bào)表的簡單使用

    這篇文章給大家介紹了如何畫一個報(bào)表模板,這里介紹下畫表格需要用到的組件,文中通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-10-10
  • SpringBoot2.0整合Shiro框架實(shí)現(xiàn)用戶權(quán)限管理的示例

    SpringBoot2.0整合Shiro框架實(shí)現(xiàn)用戶權(quán)限管理的示例

    這篇文章主要介紹了SpringBoot2.0整合Shiro框架實(shí)現(xiàn)用戶權(quán)限管理的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Java URLDNS利用鏈分析

    Java URLDNS利用鏈分析

    文章分析了一個利用ysoserial-all.jar進(jìn)行DNS利用鏈攻擊的過程,該利用鏈利用了URL類的hashCode方法,并HashMap類的序列化和反序列化機(jī)制,通過控制hashCode的值來實(shí)現(xiàn)在反序列化時無法發(fā)起DNS請求,最后提了一種通過反射修改類的屬性值來繞過該問題的攻擊方法
    2026-04-04
  • java使用反射訪問成員變量的值示例

    java使用反射訪問成員變量的值示例

    這篇文章主要介紹了java使用反射訪問成員變量的值,結(jié)合實(shí)例形式分析了java基于反射機(jī)制操作類成員變量相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2019-07-07
  • JDK14的新特性NullPointerExceptions的使用

    JDK14的新特性NullPointerExceptions的使用

    這篇文章主要介紹了JDK14的新特性NullPointerExceptions的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • Java使用String類格式化當(dāng)前日期實(shí)現(xiàn)代碼

    Java使用String類格式化當(dāng)前日期實(shí)現(xiàn)代碼

    這篇文章主要介紹了Java使用String類格式化當(dāng)前日期實(shí)現(xiàn)代碼,需要的朋友可以參考下
    2014-02-02
  • Java簡單工廠模式詳細(xì)解釋

    Java簡單工廠模式詳細(xì)解釋

    本文主要介紹了JAVA簡單工廠模式(從現(xiàn)實(shí)生活角度理解代碼原理)的相關(guān)知識。具有很好的參考價值。下面跟著小編一起來看下吧
    2021-11-11
  • Java 生成PDF文檔的示例代碼

    Java 生成PDF文檔的示例代碼

    這篇文章主要介紹了Java 生成PDF文檔的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-08-08

最新評論

邵东县| 林州市| 永德县| 讷河市| 宁化县| 田阳县| 丹巴县| 宁明县| 黑山县| 阿城市| 威海市| 德化县| 东阳市| 房产| 元江| 新化县| 乌拉特后旗| 精河县| 三台县| 丹东市| 苍梧县| 彭水| 西华县| 江西省| 秦皇岛市| 和政县| 光山县| 华坪县| 吉木萨尔县| 大方县| 望都县| 宝清县| 共和县| 萝北县| 弋阳县| 榆林市| 晋江市| 大悟县| 册亨县| 汉源县| 绥化市|