キャッシング

Spring Framework は、アプリケーションにキャッシュを透過的に追加するためのサポートを提供します。基本的に、抽象化はメソッドにキャッシュを適用するため、キャッシュで利用可能な情報に基づいて実行回数を減らすことができます。キャッシングロジックは、呼び出し側に干渉することなく、透過的に適用されます。Spring Boot は、@EnableCaching アノテーションを使用してキャッシュのサポートが有効になっている限り、キャッシュインフラストラクチャを自動構成します。

詳細については、Spring Framework リファレンスの関連セクションを確認してください。

簡単に言うと、サービスのオペレーションにキャッシングを追加するには、次の例に示すように、メソッドに関連するアノテーションを追加します。

  • Java

  • Kotlin

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

@Component
public class MyMathService {

	@Cacheable("piDecimals")
	public int computePiDecimal(int precision) {
		...
	}

}
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Component

@Component
class MyMathService {

	@Cacheable("piDecimals")
	fun computePiDecimal(precision: Int): Int {
		...
	}

}

この例は、潜在的にコストのかかる操作でのキャッシュの使用を示しています。computePiDecimal を呼び出す前に、抽象化は i 引数に一致する piDecimals キャッシュ内のエントリを探します。エントリが見つかった場合、キャッシュ内のコンテンツはすぐに呼び出し元に返され、メソッドは呼び出されません。それ以外の場合、メソッドが呼び出され、値を返す前にキャッシュが更新されます。

標準の JSR-107(JCache)アノテーション(@CacheResult など)を透過的に使用することもできます。ただし、Spring Cache アノテーションと JCache アノテーションを混在させないでください。

特定のキャッシュライブラリを追加しない場合、Spring Boot はメモリ内の同時マップを使用する単純なプロバイダーを自動構成します。キャッシュが必要な場合(前の例の piDecimals など)、このプロバイダーがキャッシュを作成します。単純なプロバイダーは、本番環境での使用にはあまりお勧めしませんが、使い始めて、機能を理解していることを確認するには最適です。使用するキャッシュプロバイダーについて決めたら、必ずそのドキュメントを読んで、アプリケーションが使用するキャッシュを構成する方法を理解しましょう。ほぼすべてのプロバイダーでは、アプリケーションで使用するすべてのキャッシュを明示的に構成する必要があります。spring.cache.cache-names プロパティで定義されたデフォルトのキャッシュをカスタマイズする方法を提供するものもあります。

キャッシュからデータを透過的に更新または削除することもできます。

サポートされているキャッシュプロバイダー

キャッシュ抽象化は実際のストアを提供せず、org.springframework.cache.Cache および org.springframework.cache.CacheManager インターフェースによって具体化される抽象化に依存します。

型 CacheManager の Bean または cacheResolver という名前の CacheResolver を定義していない場合(CachingConfigurer (Javadoc) を参照)、Spring Boot は以下のプロバイダーを(示された順序で)検出しようとします。

CacheManager が Spring Boot によって自動構成されている場合は、spring.cache.type プロパティを設定することで特定のキャッシュプロバイダーを強制できます。特定の環境 (テストなど) で no-op キャッシュを使用する必要がある場合は、このプロパティを使用します。
spring-boot-starter-cache 「スターター」を使用して、基本的なキャッシュの依存関係をすばやく追加します。スターターは spring-context-support を持ち込みます。依存関係を手動で追加する場合、JCache または Caffeine サポートを使用するには、spring-context-support を含める必要があります。

CacheManager が Spring Boot によって自動構成されている場合は、CacheManagerCustomizer インターフェースを実装する Bean を公開することにより、完全に初期化される前に構成をさらに調整できます。次の例では、null 値を基になるマップに渡してはならないことを示すフラグを設定します。

  • Java

  • Kotlin

import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCacheManagerConfiguration {

	@Bean
	public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
		return (cacheManager) -> cacheManager.setAllowNullValues(false);
	}

}
import org.springframework.boot.autoconfigure.cache.CacheManagerCustomizer
import org.springframework.cache.concurrent.ConcurrentMapCacheManager
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration

@Configuration(proxyBeanMethods = false)
class MyCacheManagerConfiguration {

	@Bean
	fun cacheManagerCustomizer(): CacheManagerCustomizer<ConcurrentMapCacheManager> {
		return CacheManagerCustomizer { cacheManager ->
			cacheManager.isAllowNullValues = false
		}
	}

}
上記の例では、自動構成された ConcurrentMapCacheManager が予期されています。そうでない場合(独自の構成を提供したか、別のキャッシュプロバイダーが自動構成された場合)、カスタマイザーはまったく呼び出されません。カスタマイザーは必要な数だけ持つことができ、@Order または Ordered を使用してオーダーすることもできます。

汎用

コンテキストが少なくとも 1 つの org.springframework.cache.Cache Bean を定義している場合、汎用キャッシングが使用されます。その型のすべての Bean をラップする CacheManager が作成されます。

JCache (JSR-107)

JCache (英語) は、クラスパスに javax.cache.spi.CachingProvider が存在することでブートストラップされ(つまり、JSR-107 準拠のキャッシュライブラリがクラスパスに存在します)、JCacheCacheManager は spring-boot-starter-cache 「スターター」によって提供されます。さまざまな準拠ライブラリが利用可能であり、Spring Boot は Ehcache 3、Hazelcast、Infinispan の依存関係管理を提供します。他の準拠ライブラリも追加できます。

複数のプロバイダーが存在する場合がありますが、その場合はプロバイダーを明示的に指定する必要があります。JSR-107 標準が構成ファイルの場所を定義する標準化された方法を強制しない場合でも、Spring Boot は、次の例に示すように、実装の詳細でキャッシュを設定するために最善を尽くします。

  • プロパティ

  • YAML

spring.cache.jcache.provider=com.example.MyCachingProvider
spring.cache.jcache.config=classpath:example.xml
# Only necessary if more than one provider is present
spring:
  cache:
    jcache:
      provider: "com.example.MyCachingProvider"
      config: "classpath:example.xml"
キャッシュライブラリがネイティブ実装と JSR-107 サポートの両方を提供する場合、Spring Boot は JSR-107 サポートを優先するため、別の JSR-107 実装に切り替えると同じ機能を使用できます。
Spring Boot は Hazelcast を一般的にサポートしています。単一の HazelcastInstance が使用可能な場合、spring.cache.jcache.config プロパティが指定されていない限り、CacheManager にも自動的に再利用されます。

基になる javax.cache.cacheManager をカスタマイズするには、2 つの方法があります。

  • spring.cache.cache-names プロパティを設定することにより、起動時にキャッシュを作成できます。カスタム javax.cache.configuration.Configuration Bean が定義されている場合、それを使用してカスタマイズします。

  • org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer Bean は、完全なカスタマイズのために CacheManager を参照して呼び出されます。

標準 javax.cache.CacheManager Bean が定義されている場合、抽象化が期待する org.springframework.cache.CacheManager 実装で自動的にラップされます。それ以上のカスタマイズは適用されません。

Hazelcast

Spring Boot は Hazelcast を一般的にサポートしていますHazelcastInstance が自動構成され、com.hazelcast:hazelcast-spring がクラスパス上にある場合、CacheManager に自動的にラップされます。

Hazelcast は、JCache 準拠のキャッシュとして、または Spring CacheManager 準拠のキャッシュとして使用できます。spring.cache.type を hazelcast に設定すると、Spring Boot は CacheManager ベースの実装を使用します。Hazelcast を JCache 準拠のキャッシュとして使用する場合は、spring.cache.type を jcache に設定します。複数の JCache 準拠のキャッシュプロバイダーがあり、強制的に Hazelcast を使用する場合は、JCache プロバイダーを明示的に設定する必要があります。

Infinispan

Infinispan (英語) にはデフォルトの構成ファイルの場所がないため、明示的に指定する必要があります。それ以外の場合、デフォルトのブートストラップが使用されます。

  • プロパティ

  • YAML

spring.cache.infinispan.config=infinispan.xml
spring:
  cache:
    infinispan:
      config: "infinispan.xml"

spring.cache.cache-names プロパティを設定することにより、起動時にキャッシュを作成できます。カスタム ConfigurationBuilder Bean が定義されている場合、それを使用してキャッシュをカスタマイズします。

Spring Boot の Jakarta EE 9 ベースラインと互換性を持たせるには、Infinispan の -jakarta モジュールを使用する必要があります。-jakarta バリアントを持つすべてのモジュールについて、そのバリアントを標準モジュールの代わりに使用する必要があります。例: infinispan-core および infinispan-commons の代わりに、それぞれ infinispan-core-jakarta および infinispan-commons-jakarta を使用する必要があります。

Couchbase

Spring Data、Couchbase が使用可能で、Couchbase が構成されている場合、CouchbaseCacheManager が自動的に構成されます。spring.cache.cache-names プロパティを設定することで起動時に追加のキャッシュを作成でき、spring.cache.couchbase.* プロパティを使用してキャッシュのデフォルトを構成できます。たとえば、次の構成では、エントリの有効期限が 10 分である cache1 および cache2 キャッシュが作成されます。

  • プロパティ

  • YAML

spring.cache.cache-names=cache1,cache2
spring.cache.couchbase.expiration=10m
spring:
  cache:
    cache-names: "cache1,cache2"
    couchbase:
      expiration: "10m"

構成をさらに制御する必要がある場合は、CouchbaseCacheManagerBuilderCustomizer Bean の登録を検討してください。次の例は、cache1 および cache2 の特定のエントリの有効期限を設定するカスタマイザを示しています。

  • Java

  • Kotlin

import java.time.Duration;

import org.springframework.boot.autoconfigure.cache.CouchbaseCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration;

@Configuration(proxyBeanMethods = false)
public class MyCouchbaseCacheManagerConfiguration {

	@Bean
	public CouchbaseCacheManagerBuilderCustomizer myCouchbaseCacheManagerBuilderCustomizer() {
		return (builder) -> builder
				.withCacheConfiguration("cache1", CouchbaseCacheConfiguration
						.defaultCacheConfig().entryExpiry(Duration.ofSeconds(10)))
				.withCacheConfiguration("cache2", CouchbaseCacheConfiguration
						.defaultCacheConfig().entryExpiry(Duration.ofMinutes(1)));

	}

}
import org.springframework.boot.autoconfigure.cache.CouchbaseCacheManagerBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration
import java.time.Duration

@Configuration(proxyBeanMethods = false)
class MyCouchbaseCacheManagerConfiguration {

	@Bean
	fun myCouchbaseCacheManagerBuilderCustomizer(): CouchbaseCacheManagerBuilderCustomizer {
		return CouchbaseCacheManagerBuilderCustomizer { builder ->
			builder
				.withCacheConfiguration(
					"cache1", CouchbaseCacheConfiguration
						.defaultCacheConfig().entryExpiry(Duration.ofSeconds(10))
				)
				.withCacheConfiguration(
					"cache2", CouchbaseCacheConfiguration
						.defaultCacheConfig().entryExpiry(Duration.ofMinutes(1))
				)
		}
	}

}

Redis

Redis (英語) が使用可能で構成されている場合、RedisCacheManager は自動構成されます。spring.cache.cache-names プロパティを設定することにより、起動時に追加のキャッシュを作成でき、spring.cache.redis.* プロパティを使用してキャッシュのデフォルトを設定できます。たとえば、次の構成では、存続時間 10 分で cache1 および cache2 キャッシュを作成します。

  • プロパティ

  • YAML

spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=10m
spring:
  cache:
    cache-names: "cache1,cache2"
    redis:
      time-to-live: "10m"
デフォルトでは、2 つの個別のキャッシュが同じキーを使用する場合、Redis に重複するキーがなく、無効な値を返すことができないように、キープレフィックスが追加されます。独自の RedisCacheManager を作成する場合は、この設定を有効にしておくことを強くお勧めします。
独自の RedisCacheConfiguration@Bean を追加することにより、デフォルト構成を完全に制御できます。これは、デフォルトの直列化戦略をカスタマイズする必要がある場合に役立ちます。

構成をさらに制御する必要がある場合は、RedisCacheManagerBuilderCustomizer Bean の登録を検討してください。次の例は、cache1 および cache2 の特定の存続時間を構成するカスタマイザーを示しています。

  • Java

  • Kotlin

import java.time.Duration;

import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;

@Configuration(proxyBeanMethods = false)
public class MyRedisCacheManagerConfiguration {

	@Bean
	public RedisCacheManagerBuilderCustomizer myRedisCacheManagerBuilderCustomizer() {
		return (builder) -> builder
				.withCacheConfiguration("cache1", RedisCacheConfiguration
						.defaultCacheConfig().entryTtl(Duration.ofSeconds(10)))
				.withCacheConfiguration("cache2", RedisCacheConfiguration
						.defaultCacheConfig().entryTtl(Duration.ofMinutes(1)));

	}

}
import org.springframework.boot.autoconfigure.cache.RedisCacheManagerBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.data.redis.cache.RedisCacheConfiguration
import java.time.Duration

@Configuration(proxyBeanMethods = false)
class MyRedisCacheManagerConfiguration {

	@Bean
	fun myRedisCacheManagerBuilderCustomizer(): RedisCacheManagerBuilderCustomizer {
		return RedisCacheManagerBuilderCustomizer { builder ->
			builder
				.withCacheConfiguration(
					"cache1", RedisCacheConfiguration
						.defaultCacheConfig().entryTtl(Duration.ofSeconds(10))
				)
				.withCacheConfiguration(
					"cache2", RedisCacheConfiguration
						.defaultCacheConfig().entryTtl(Duration.ofMinutes(1))
				)
		}
	}

}

Caffeine

Caffeine [GitHub] (英語) は、Guava のサポートに代わる Guava のキャッシュの Java 8 の書き換えです。Caffeine が存在する場合、CaffeineCacheManager (spring-boot-starter-cache 「スターター」によって提供される)が自動構成されます。キャッシュは、起動時に spring.cache.cache-names プロパティを設定することで作成でき、次のいずれか(示された順序)でカスタマイズできます。

  1. spring.cache.caffeine.spec によって定義されたキャッシュ仕様

  2. com.github.benmanes.caffeine.cache.CaffeineSpec Bean が定義されています

  3. com.github.benmanes.caffeine.cache.Caffeine Bean が定義されています

たとえば、次の構成では、最大サイズが 500 で存続時間が 10 分の cache1 および cache2 キャッシュが作成されます。

  • プロパティ

  • YAML

spring.cache.cache-names=cache1,cache2
spring.cache.caffeine.spec=maximumSize=500,expireAfterAccess=600s
spring:
  cache:
    cache-names: "cache1,cache2"
    caffeine:
      spec: "maximumSize=500,expireAfterAccess=600s"

com.github.benmanes.caffeine.cache.CacheLoader Bean が定義されている場合、CaffeineCacheManager に自動的に関連付けられます。CacheLoader はキャッシュマネージャーによって管理されるすべてのキャッシュに関連付けられるため、CacheLoader<Object, Object> として定義する必要があります。自動構成では、他の一般的な型は無視されます。

Cache2k

Cache2k (英語) はメモリ内キャッシュです。Cache2kSpring 統合が存在する場合、SpringCache2kCacheManager は自動構成されます。

spring.cache.cache-names プロパティを設定することにより、起動時にキャッシュを作成できます。キャッシュのデフォルトは、Cache2kBuilderCustomizer Bean を使用してカスタマイズできます。次の例は、キャッシュの容量を 5 分の有効期限で 200 エントリに構成するカスタマイザーを示しています。

  • Java

  • Kotlin

import java.util.concurrent.TimeUnit;

import org.springframework.boot.autoconfigure.cache.Cache2kBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration(proxyBeanMethods = false)
public class MyCache2kDefaultsConfiguration {

	@Bean
	public Cache2kBuilderCustomizer myCache2kDefaultsCustomizer() {
		return (builder) -> builder.entryCapacity(200)
				.expireAfterWrite(5, TimeUnit.MINUTES);
	}

}
import org.springframework.boot.autoconfigure.cache.Cache2kBuilderCustomizer
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.util.concurrent.TimeUnit

@Configuration(proxyBeanMethods = false)
class MyCache2kDefaultsConfiguration {

	@Bean
	fun myCache2kDefaultsCustomizer(): Cache2kBuilderCustomizer {
		return Cache2kBuilderCustomizer { builder ->
			builder.entryCapacity(200)
				.expireAfterWrite(5, TimeUnit.MINUTES)
		}
	}
}

シンプル

他のプロバイダーが見つからない場合は、ConcurrentHashMap をキャッシュストアとして使用する単純な実装が構成されます。アプリケーションにキャッシングライブラリが存在しない場合、これがデフォルトです。デフォルトでは、キャッシュは必要に応じて作成されますが、cache-names プロパティを設定することにより、使用可能なキャッシュのリストを制限できます。たとえば、cache1 および cache2 キャッシュのみが必要な場合は、cache-names プロパティを次のように設定します。

  • プロパティ

  • YAML

spring.cache.cache-names=cache1,cache2
spring:
  cache:
    cache-names: "cache1,cache2"

そうすると、アプリケーションがリストにないキャッシュを使用する場合、実行時にキャッシュが必要になりますが、起動時は失敗します。これは、宣言されていないキャッシュを使用する場合の「実際の」キャッシュプロバイダーの動作に似ています。

なし

構成に @EnableCaching が存在する場合、適切なキャッシュ構成も期待されます。カスタム CacheManager がある場合は、必要に応じてオーバーライドできるように、それを別の @Configuration クラスで定義することを検討してください。None はテストに役立つ no-op 実装を使用し、スライステストはデフォルトで @AutoConfigureCache 経由でそれを使用します。

特定の環境で自動構成キャッシュマネージャーではなく no-op キャッシュを使用する必要がある場合は、次の例に示すように、キャッシュ型を none に設定します。

  • プロパティ

  • YAML

spring.cache.type=none
spring:
  cache:
    type: "none"