キャッシング

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

詳細については、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 を呼び出す前に、抽象化は precision 引数に一致する piDecimals キャッシュ内のエントリを探します。エントリが見つかった場合、キャッシュ内のコンテンツはすぐに呼び出し元に返され、メソッドは呼び出されません。それ以外の場合、メソッドが呼び出され、値を返す前にキャッシュが更新されます。

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

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

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

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

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

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

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

CacheManager (Javadoc) が Spring Boot によって自動構成される場合、CacheManagerCustomizer (Javadoc) インターフェースを実装する 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 (Javadoc) が想定されています。そうでない場合 (独自の構成を指定した場合、または別のキャッシュプロバイダーが自動構成された場合)、カスタマイザーはまったく呼び出されません。必要な数のカスタマイザーを用意でき、@Order (Javadoc) または Ordered (Javadoc) を使用して順序を指定することもできます。

汎用

コンテキストで少なくとも 1 つの Cache (Javadoc) Bean が定義されている場合は、汎用キャッシュが使用されます。その型のすべての Bean をラップする CacheManager (Javadoc) が作成されます。

JCache (JSR-107)

JCache (英語) は、クラスパス上に CachingProvider (英語) が存在することでブートストラップされます (つまり、クラスパス上に JSR-107 準拠のキャッシュライブラリが存在します)。また、JCacheCacheManager (Javadoc) は 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 (英語) でも自動的に再利用されます。

基盤となる CacheManager (英語) をカスタマイズするには、次の 2 つの方法があります。

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

  • JCacheManagerCustomizer (Javadoc) Bean は、完全なカスタマイズのために CacheManager (英語) の参照を使用して呼び出されます。

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

Hazelcast

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

Hazelcast は、JCache 準拠のキャッシュとして、または Spring CacheManager (Javadoc) 準拠のキャッシュとして使用できます。spring.cache.type を hazelcast に設定すると、Spring Boot は CacheManager (Javadoc) ベースの実装を使用します。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 (Javadoc) が自動的に構成されます。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 (Javadoc) 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 (Javadoc) が自動的に構成されます。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 (Javadoc) を作成する場合は、この設定を有効にしておくことを強くお勧めします。
独自の RedisCacheConfiguration (Javadoc) @Bean (Javadoc) を追加することで、デフォルト構成を完全に制御できます。これは、デフォルトの直列化戦略をカスタマイズする必要がある場合に役立ちます。

構成をさらに細かく制御する必要がある場合は、RedisCacheManagerBuilderCustomizer (Javadoc) 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 (Javadoc) (spring-boot-starter-cache スターターによって提供) が自動的に構成されます。キャッシュは、spring.cache.cache-names プロパティを設定することで起動時に作成でき、次のいずれか (示された順序) でカスタマイズできます。

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

  2. CaffeineSpec (英語) Bean は定義される

  3. 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"

CacheLoader (英語) Bean が定義されている場合、CaffeineCacheManager (Javadoc) に自動的に関連付けられます。CacheLoader (英語) はキャッシュマネージャーによって管理されるすべてのキャッシュに関連付けられるため、CacheLoader<Object, Object> として定義する必要があります。自動構成では、他の汎用型は無視されます。

Cache2k

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

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

  • 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 (標準 Javadoc) を使用する単純な実装が構成されます。アプリケーションにキャッシュライブラリが存在しない場合は、これがデフォルトです。デフォルトでは、キャッシュは必要に応じて作成されますが、cache-names プロパティを設定することで、使用可能なキャッシュのリストを制限できます。たとえば、cache1 および cache2 キャッシュのみが必要な場合は、cache-names プロパティを次のように設定します。

  • プロパティ

  • YAML

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

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

なし

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

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

  • プロパティ

  • YAML

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