知識庫 / Spring RSS 訂閱

Spring 緩存指南

Spring
HongKong
4
02:53 PM · Dec 06 ,2025

1. 簡介

在本教程中,我們將學習如何使用 Spring 中的緩存抽象,並通常提高我們系統的性能。

我們將啓用簡單的緩存機制,用於一些實際方法示例,並通過智能緩存管理來有效地提高這些調用的性能。

2. 快速入門

在開始實施緩存之前,我們需要確保我們的 Spring Boot 應用程序具有必要的依賴項,以便支持緩存。

2.1. 使用 Spring Boot

要開始在 Spring Boot 應用程序中緩存,Spring 提供了一個易於集成的緩存抽象,可以使用 spring-boot-starter-cache starter 包輕鬆集成:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
    <version>3.5.7</version>
</dependency>

在底層,啓動器引入了 spring-context-support 模塊。

2.2. 使用 Spring Core

Spring Core 核心緩存抽象位於 spring-context 模塊中。因此,在使用 Maven 時,我們的 pom.xml 應包含以下依賴項:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>6.2.11</version>
</dependency>

有趣的是,還有一個名為 spring-context-support 的模塊,它位於 spring-context 模塊之上,並提供了一些由 EhCache 或 Caffeine 等技術支持的 CacheManagers。 如果我們想使用它們作為我們的緩存存儲,則需要使用 spring-context-support 模塊:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>6.2.11</version>
</dependency>

由於 spring-context-support 模塊間接依賴 spring-context 模塊,因此無需為 spring-context 模塊單獨聲明依賴。

3. 啓用緩存

要啓用 Spring 中的緩存,我們可以利用註解,類似於我們在框架內激活其他配置級別功能的方式。

在 Spring Boot 應用程序中,類路徑上僅存在 starter 包以及 EnableCaching 註解,就足以註冊相同的 ConcurrentMapCacheManager。

此外,我們還可以使用一個或多個 CacheManagerCustomizer&lt;T&gt; Bean 來自定義 自動配置 CacheManager

@Component
public class SimpleCacheCustomizer 
  implements CacheManagerCustomizer<ConcurrentMapCacheManager> {

    @Override
    public void customize(ConcurrentMapCacheManager cacheManager) {
        cacheManager.setCacheNames(asList("users", "transactions"));
    }
}

CacheAutoConfiguration》自動配置會拾取這些自定義配置器,並在其完全初始化之前將其應用於當前的 CacheManager

我們可以通過在任何配置類中添加 @EnableCaching 註解來啓用緩存功能:

@Configuration
@EnableCaching
public class CachingConfig {

    @Bean
    public CacheManager cacheManager() {
        return new ConcurrentMapCacheManager("addresses");
    }
}

注意:在啓用緩存後,為了最小化配置,必須註冊一個 cacheManager

4. 使用緩存與註釋

一旦我們啓用了緩存,下一步就是將緩存行為綁定到帶有聲明式註解的方法上。

4.1. @Cacheable

要啓用方法緩存行為的最簡單方法是使用 @Cacheable 標記該方法,並使用緩存名稱來參數化該方法:

@Cacheable("addresses")
public String getAddress(Customer customer) {...}

調用 getAddress() 方法首先會檢查緩存 addresses,然後在真正調用方法之前緩存結果,並緩存結果。

雖然在大多數情況下,一個緩存就足夠了,但 Spring 框架也支持將多個緩存作為參數傳遞:

@Cacheable({"addresses", "directory"})
public String getAddress(Customer customer) {...}

在這種情況下,如果任何緩存都包含所需的結果,則結果將被返回,並且該方法不會被調用。

4.2. <em @CacheEvict</em>>

現在,如果將所有方法都標記為 <em @Cacheable</em>>,會產生什麼問題呢?

問題在於大小。我們不想用那些不經常使用的值填充緩存。緩存可能會變得非常大,而且速度很快,我們可能會持有大量過時或未使用的數據。

我們可以使用 <em @CacheEvict</em>> 註解來指示刪除一個或多個/所有值,以便重新加載新鮮的值到緩存中:

@CacheEvict(value="addresses", allEntries=true)
public String getAddress(Customer customer) {...}

我們在這裏使用額外的參數 allEntries 與緩存一起用於清空緩存;這將清除緩存中的所有 addresses 條目,併為新數據做準備。

4.3. @CachePut

While @CacheEvict reduces the overhead of looking up entries in a large cache by removing stale and unused entries, we want to 避免過多地從緩存中移除數據

Instead, we selectively update the entries whenever we alter them.

With the @CachePut annotation, we can update the content of the cache without interfering with the method execution. That is, the method will always be executed and the result cached:

@CachePut(value="addresses")
public String getAddress(Customer customer) {...}

<p><em>@Cacheable</em> 和 <em>@CachePut</em> 的區別在於,<em>@Cacheable</em> 會 <strong >跳過執行方法</strong>,而 <em>@CachePut</em> 會 <strong >實際執行方法</strong>,然後將結果放入緩存。</p>

4.4. 緩存 (@Caching)

如果我們要為緩存方法使用相同類型的多個註解,請看以下一個錯誤的例子:

@CacheEvict("addresses")
@CacheEvict(value="directory", key=customer.name)
public String getAddress(Customer customer) {...}

上述代碼由於 Java 不允許為同一方法聲明相同類型的多個註解而編譯失敗。

解決上述問題的辦法是:

@Caching(evict = { 
  @CacheEvict("addresses"), 
  @CacheEvict(value="directory", key="#customer.name") })
public String getAddress(Customer customer) {...}

如代碼片段所示,我們可以使用 多重緩存註解,並通過 @Caching 實現自定義緩存邏輯。

4.5. @CacheConfig

通過使用 <em/>@CacheConfig</em/> 註解,我們可以將一些緩存配置集中到類級別,從而避免在多個地方重複聲明:

@CacheConfig("addresses")
public class CustomerDataService {

    @Cacheable
    public String getAddress(Customer customer) {...}

    // ...
}

5. 條件緩存

有時,緩存可能無法很好地適用於所有方法的情況。

再次使用我們之前在 @CachePut 註解中的示例,它將每次都執行方法並緩存結果:

@CachePut(value="addresses")
public String getAddress(Customer customer) {...}

5.1. 條件參數

如果想要對標註的激活時機進行更精細的控制,我們可以使用條件參數來參數化 <em >@CachePut</em>,該參數接受一個 SpEL 表達式,並確保緩存結果基於評估該表達式進行:

@CachePut(value="addresses", condition="#customer.name=='Tom'")
public String getAddress(Customer customer) {...}

5.2. 未指定參數

我們可以通過 unless 參數,根據方法的輸出而非輸入來控制緩存行為:

@CachePut(value="addresses", unless="#result.length()<64")
public String getAddress(Customer customer) {...}

上述註釋將緩存地址,除非它們長度小於 64 個字符。

需要注意的是,conditionunless 參數可以與所有緩存註釋一起使用。

這種條件緩存對於管理大型結果非常有效。它還可用於根據輸入參數自定義行為,而不是強制所有操作都採用通用行為。

6. 基於Java的緩存

以下是等效的Java配置:

@Configuration
@EnableCaching
public class CachingConfig {

    @Bean
    public CacheManager cacheManager() {
        SimpleCacheManager cacheManager = new SimpleCacheManager();
        cacheManager.setCaches(Arrays.asList(
          new ConcurrentMapCache("directory"), 
          new ConcurrentMapCache("addresses")));
        return cacheManager;
    }
}

以下是我們的 CustomerDataService

@Component
public class CustomerDataService {
 
    @Cacheable(value = "addresses", key = "#customer.name")
    public String getAddress(Customer customer) {
        return customer.getAddress();
    }
}

7. 結論

在本文中,我們探討了 Spring 緩存的基礎知識,重點介紹了諸如 <em @Cacheable</em>, <em @CacheEvict</em>, 和 <em @CachePut</em> 等註解。 通過明智地使用緩存,我們可以顯著提高應用程序的性能,尤其是在存在重複數據檢索或昂貴方法調用領域。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.