32. Caching

Spring 框架提供了对向应用程序透明添加缓存的支持。从本质上讲,抽象将缓存应用于方法,从而根据缓存中可用的信息减少执行次数。缓存逻辑是透明应用的,不会对调用者造成任何干扰。只要通过@EnableCachingComments 启用了缓存支持,Spring Boot 就会自动配置缓存基础结构。

Note

查看 Spring 框架参考的relevant section以获得更多详细信息。

简而言之,将缓存添加到服务的操作就像将相关 Comments 添加到其方法一样容易,如以下示例所示:

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

@Component
public class MathService {

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

}

本示例说明了在可能耗资巨大的操作上使用缓存的方法。在调用computePiDecimal之前,抽象将在piDecimals缓存中查找与i参数匹配的条目。如果找到条目,则高速缓存中的内容会立即返回给调用方,并且不会调用该方法。否则,将调用该方法,并在返回值之前更新缓存。

Warning

您还可以透明地使用标准 JSR-107(JCache)注解(例如@CacheResult)。但是,我们强烈建议您不要混合使用 Spring Cache 和 JCache 注解。

如果您不添加任何特定的缓存库,Spring Boot 会自动配置一个使用内存中并发 Map 的simple provider。需要缓存时(例如上例中的piDecimals),此提供程序将为您创建它。实际上,不建议将简单提供程序用于生产用途,但是它对于 Starter 并确保您了解功能非常有用。确定要使用的缓存提供程序后,请确保阅读其文档,以了解如何配置应用程序使用的缓存。几乎所有提供程序都要求您显式配置在应用程序中使用的每个缓存。有些提供了一种自定义spring.cache.cache-names属性定义的默认缓存的方法。

Tip

也可以透明地从缓存中updateevict数据。

32.1 支持的缓存提供程序

缓存抽象不提供实际的存储,而是依赖于org.springframework.cache.Cacheorg.springframework.cache.CacheManager接口实现的抽象。

如果尚未定义类型CacheManager或名为cacheResolverCacheResolver(请参见CachingConfigurer),则 Spring Boot 尝试检测以下提供程序(按指示的 Sequences):

Tip

也可以通过设置spring.cache.type属性来“强制”特定的缓存提供程序。如果需要在某些环境(例如测试)中完全禁用缓存,请使用此属性。

Tip

使用spring-boot-starter-cache“Starter”快速添加基本的缓存依赖项。启动器带来spring-context-support。如果手动添加依赖项,则必须包含spring-context-support才能使用 JCache,EhCache 2.x 或 Guava 支持。

如果CacheManager是由 Spring Boot 自动配置的,则可以通过公开实现CacheManagerCustomizer接口的 bean,在完全初始化之前进一步调整其配置。下面的示例设置一个标志,指示应该将空值向下传递到基础 Map:

@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
	return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
		@Override
		public void customize(ConcurrentMapCacheManager cacheManager) {
			cacheManager.setAllowNullValues(false);
		}
	};
}

Note

在前面的示例中,应使用自动配置的ConcurrentMapCacheManager。如果不是这种情况(您提供了自己的配置,或者自动配置了其他缓存提供程序),则根本不会调用定制程序。您可以根据需要拥有任意数量的定制程序,也可以使用@OrderOrdered对其进行排序。

32.1.1 Generic

如果上下文至少定义了一个org.springframework.cache.Cache bean,则使用通用缓存。创建一个CacheManager包装该类型的所有 bean。

32.1.2 JCache(JSR-107)

JCache通过 Classpath 上存在javax.cache.spi.CachingProvider进行引导(即,Classpath 上存在符合 JSR-107 的缓存库),并且JCacheCacheManagerspring-boot-starter-cache“启动程序”提供。提供了各种兼容的库,Spring Boot 为 Ehcache 3,Hazelcast 和 Infinispan 提供了依赖 Management。也可以添加任何其他兼容的库。

可能会出现多个提供者,在这种情况下,必须明确指定提供者。即使 JSR-107 标准没有强制采用标准化的方式来定义配置文件的位置,Spring Boot 也会尽其所能以设置具有实现细节的缓存,如以下示例所示:

# Only necessary if more than one provider is present
spring.cache.jcache.provider=com.acme.MyCachingProvider
spring.cache.jcache.config=classpath:acme.xml

Note

当缓存库同时提供本机实现和 JSR-107 支持时,Spring Boot 会首选 JSR-107 支持,因此,如果您切换到其他 JSR-107 实现,则可以使用相同的功能。

Tip

Spring Boot 具有对 Hazelcast 的常规支持。如果有一个HazelcastInstance可用,则除非指定spring.cache.jcache.config属性,否则它也会自动为CacheManager重用。

自定义基础javax.cache.cacheManager的方法有两种:

Tip

如果定义了一个标准的javax.cache.CacheManager bean,它将自动包装在抽象期望的org.springframework.cache.CacheManager实现中。不再对其应用定制。

32.1.3 EhCache 2.x

如果可以在 Classpath 的根目录下找到名为ehcache.xml的文件,则使用EhCache2.x。如果找到 EhCache 2.x,则使用spring-boot-starter-cache“启动程序”提供的EhCacheCacheManager来引导缓存 Management 器。也可以提供备用配置文件,如以下示例所示:

spring.cache.ehcache.config=classpath:config/another-config.xml

32.1.4 Hazelcast

Spring Boot 具有对 Hazelcast 的常规支持。如果已自动配置HazelcastInstance,则会自动将其包装在CacheManager中。

32.1.5 Infinispan

Infinispan没有默认配置文件位置,因此必须明确指定。否则,将使用默认的引导程序。

spring.cache.infinispan.config=infinispan.xml

可以在启动时通过设置spring.cache.cache-names属性来创建缓存。如果定义了自定义ConfigurationBuilder bean,则用于自定义缓存。

Note

Spring Boot 对 Infinispan 的支持仅限于嵌入式模式,并且非常基础。如果您需要更多选择,则应该使用官方的 Infinispan Spring Boot 启动程序。有关更多详细信息,请参见Infinispan's documentation

32.1.6 Couchbase

如果Couchbase Java Client 端和couchbase-spring-cache实现可用且 Couchbase 为configured,则将自动配置CouchbaseCacheManager。也可以通过设置spring.cache.cache-names属性在启动时创建其他缓存。这些缓存在自动配置的Bucket上运行。您还可以*使用定制程序在另一个Bucket上创建其他缓存。假设您在“主” Bucket上需要两个缓存(cache1cache2),在(另一个)Bucket上需要一个缓存(cache3)的自定义时间为 2 秒。您可以通过配置创建前两个缓存,如下所示:

spring.cache.cache-names=cache1,cache2

然后,您可以定义一个@Configuration类来配置额外的Bucketcache3缓存,如下所示:

@Configuration
public class CouchbaseCacheConfiguration {

	private final Cluster cluster;

	public CouchbaseCacheConfiguration(Cluster cluster) {
		this.cluster = cluster;
	}

	@Bean
	public Bucket anotherBucket() {
		return this.cluster.openBucket("another", "secret");
	}

	@Bean
	public CacheManagerCustomizer<CouchbaseCacheManager> cacheManagerCustomizer() {
		return c -> {
			c.prepareCache("cache3", CacheBuilder.newInstance(anotherBucket())
					.withExpiration(2));
		};
	}

}

此示例配置重复使用通过自动配置创建的Cluster

32.1.7 Redis

如果Redis可用并已配置,则将自动配置RedisCacheManager。可以通过设置spring.cache.cache-names属性在启动时创建其他缓存,并且可以使用spring.cache.redis.*属性配置缓存默认值。例如,以下配置创建了“生存时间”为 10 分钟的cache1cache2缓存:

spring.cache.cache-names=cache1,cache2
spring.cache.redis.time-to-live=600000

Note

默认情况下,添加密钥前缀,以便如果两个单独的缓存使用相同的密钥,则 Redis 不会有重叠的密钥,并且不能返回无效值。如果您创建自己的RedisCacheManager,强烈建议您启用此设置。

Tip

您可以添加自己的RedisCacheConfiguration @Bean,从而完全控制配置。如果您要自定义序列化策略,这将很有用。

32.1.8 Caffeine

Caffeine是对 Guava 缓存的 Java 8 重写,取代了对 Guava 的支持。如果存在 Caffeine,则会自动配置CaffeineCacheManager(由spring-boot-starter-cache“Starter”提供)。缓存可以在启动时通过设置spring.cache.cache-names属性来创建,并且可以通过以下方式之一自定义(按指示的 Sequences):

例如,以下配置创建cache1cache2缓存,最大大小为 500,并且生存时间为 10 分钟

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

如果定义了com.github.benmanes.caffeine.cache.CacheLoader bean,它将自动与CaffeineCacheManager关联。由于CacheLoader将与由缓存 Management 器 Management 的* all *缓存相关联,因此必须将其定义为CacheLoader<Object, Object>。自动配置将忽略任何其他通用类型。

32.1.9 Simple

如果找不到其他提供者,则配置使用ConcurrentHashMap作为缓存存储区的简单实现。如果您的应用程序中不存在任何缓存库,则这是默认设置。默认情况下,将根据需要创建缓存,但是您可以通过设置cache-names属性来限制可用缓存的列表。例如,如果只需要cache1cache2缓存,则按如下所示设置cache-names属性:

spring.cache.cache-names=cache1,cache2

如果这样做,并且您的应用程序使用了未列出的缓存,那么当需要该缓存时,它将在运行时失败,但不会在启动时失败。这类似于使用未声明的缓存时“实际”缓存提供程序的行为。

32.1.10 None

当您的配置中包含@EnableCaching时,也需要合适的缓存配置。如果需要在某些环境中完全禁用缓存,请强制将缓存类型设置为none以使用无操作实现,如以下示例所示:

spring.cache.type=none
上一章 首页 下一章