Spring Cache 介紹

且行且码發表於2024-04-21

Spring Cache 是 Spring 提供的的快取解決方案,它並非是一個具體的快取實現,而是和 JSR107 類似的一套快取規範,基於註解並與 Spring 的無縫整合。本文主要介紹其基本概念及簡單使用。

1、簡介

1.1、Spring Cache 概述

Spring Cache 是 Spring 提供的一種快取抽象機制,用於簡化應用中的快取操作。它透過將方法的返回值快取起來,當下次呼叫同一方法時,如果傳入的引數與之前的呼叫相同,就可以直接從快取中獲取結果,而不需要再執行方法體中的程式碼,提高了系統的效能和響應速度。

Spring Cache 的特點:
宣告式快取:透過在方法上新增註解,如 @Cacheable、@CachePut、@CacheEvict 等來宣告快取的行為,無需手動編寫快取程式碼。
多種快取支援:Spring Cache 提供了對多種快取框架的支援,包括 Redis、Ehcache、Guava Cache、Caffeine 等,可以根據需要選擇合適的快取實現。
快取策略配置:可以透過配置檔案或者程式設計方式來配置快取的策略,包括快取的過期時間、快取的淘汰策略等。
註解靈活應用:透過在方法上新增不同的註解,可以實現快取的讀取、更新和清除等操作,根據業務需求進行靈活配置。
快取切面自動代理:Spring Cache 透過 AOP 技術,利用代理模式在方法執行前後攔截,自動處理快取相關的操作,對業務程式碼無侵入。

1.2、Spring Cache 註解

註解 說明
@Cacheable 標記在方法上,表示方法的返回值會被快取。當方法被呼叫時,會先檢查快取中是否存在對應的結果,如果存在,則直接返回快取中的值,如果不存在,則執行方法體,並將返回值快取起來。
@CachePut 標記在方法上,表示方法的返回值會被快取。不同於 @Cacheable,@CachePut 每次都會執行方法體,並將返回值快取起來;它通常用於更新快取。
@CacheEvict 標記在方法上,表示清除快取項。透過設定不同的屬性來清除的相應快取項,透過 key 屬性來清除特定鍵的快取項,透過 allEntries 屬性來清除所有快取項。
@Caching 用於多個快取操作的組合,可以同時使用 @Cacheable、@CachePut 和 @CacheEvict 等註解。
@CacheConfig 標記在類上,用於指定該類中所有方法的快取相關配置,包括快取名稱、快取管理器等。

這些註解透過宣告式的方式來管理快取,透過在方法上新增相應的註解,可以方便地實現快取的讀取、更新和清除等操作。同時,Spring Cache 還支援使用 SpEL 表示式來動態地指定快取的 Key 和條件等。開發者可以根據具體的業務需求選擇合適的註解來配置快取行為。

2、Spring Cache 使用

Spring Boot 中使用 Spring Cache 大概有以下步驟。

2.1、引入相關依賴

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.18</version>
    <relativePath />
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
</dependencies>

2.2、啟用快取

在啟動類上新增 @EnableCaching 註解。

@SpringBootApplication
@EnableCaching
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

2.3、引入並配置具體的快取實現

2.3.1、Caffeine 作為快取實現

A、引入依賴

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

B、配置快取(application.yml)

spring:
  cache:
    type: caffeine
    caffeine:
      spec: maximumSize=1000,expireAfterWrite=3s

spec 的配置屬性可參考 com.github.benmanes.caffeine.cache.CaffeineSpec 類。

2.3.2、JCache 作為快取實現

JCache 也是快取規範,這裡使用 Ehcache3 作為其快取實現。

A、引入依賴

<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
</dependency>
<dependency>
    <groupId>org.ehcache</groupId>
    <artifactId>ehcache</artifactId>
</dependency>

B、配置快取(application.yml)

spring:
  cache:
    type: jcache
    jcache:
      config: classpath:ehcache3.xml

C、ehcache3 配置(ehcache3.xml)

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:jsr107="http://www.ehcache.org/v3/jsr107"
        xmlns="http://www.ehcache.org/v3"
        xsi:schemaLocation="http://www.ehcache.org/v3
        http://www.ehcache.org/schema/ehcache-core-3.10.xsd
        http://www.ehcache.org/v3/jsr107
        http://www.ehcache.org/schema/ehcache-107-ext-3.10.xsd">

    <persistence directory="D:\temp"/>

    <cache alias="myCache">
        <key-type>java.lang.Integer</key-type>
        <value-type>java.lang.String</value-type>
        <expiry>
            <tti unit="minutes">5</tti>
        </expiry>
        <resources>
            <heap unit="MB">10</heap>
            <offheap unit="MB">50</offheap>
            <disk persistent="true" unit="MB">500</disk>
        </resources>
    </cache>
</config>

2.4、快取使用

根據需要在方法上新增相應註解即可。

package com.abc.general.service.impl;

import com.abc.general.service.ICacheService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class CacheServiceImpl implements ICacheService {
    @Cacheable(cacheNames = "myCache", key = "#id")
    @Override
    public String queryById(int id) {
        log.info("queryById,id={}", id);
        return "value" + id;
    }

    @CachePut(cacheNames = "myCache", key = "#id")
    @Override
    public String updateById(int id, String newValue) {
        log.info("updateById,id={},newValue={}", id, newValue);
        return newValue;
    }

    @CacheEvict(cacheNames = "myCache", key = "#id")
    @Override
    public void deleteById(int id) {
        log.info("deleteById,id={}", id);
    }
}

相關文章