缓存

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

有关更多详细信息,请查看Spring Framework参考的相关部分

简而言之,将缓存添加到服务操作就像在其方法中添加相关注释一样简单,如以下示例所示:

1
2
3
4
5
6
7
8
9
10
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参数匹配的条目。如果找到条目,则缓存中的内容会立即返回给调用者,并且不会调用该方法。否则,将调用该方法,并在返回值之前更新缓存。

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

如果您不添加任何特定的缓存库,Spring Boot会自动配置一个在内存中使用并发映射的 简单提供程序。当需要缓存时(例如piDecimals在前面的示例中),此提供程序会为您创建缓存。简单的提供程序并不是真正推荐用于生产用途,但它非常适合入门并确保您了解这些功能。当您决定使用缓存提供程序时,请务必阅读其文档以了解如何配置应用程序使用的缓存。几乎所有提供程序都要求您显式配置在应用程序中使用的每个缓存。有些提供了一种自定义spring.cache.cache-names属性定义的默认缓存的方法。

还可以透明地 更新逐出缓存中的数据。

支持的缓存提供程序

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

如果尚未定义类型的bean CacheManagerCacheResolver命名 的bean cacheResolver(请参阅参考资料 CachingConfigurer),Spring Boot会尝试检测以下提供程序(按指示的顺序):

  1. Generic
  2. JCache(JSR-107)(EhCache 3,Hazelcast,Infinispan等)
  3. EhCache 2.x
  4. Hazelcast
  5. Infinispan
  6. Couchbase
  7. Redis
  8. Caffeine
  9. Simple

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

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

如果CacheManager由Spring Boot自动配置,则可以通过公开实现该CacheManagerCustomizer接口的bean完全初始化之前进一步调整其配置 。以下示例设置一个标志,表示应将null值传递给底层映射:

1
2
3
4
5
6
7
8
9
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {
return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {
@Override
public void customize(ConcurrentMapCacheManager cacheManager) {
cacheManager.setAllowNullValues(false);
}
};
}

在前面的示例中,ConcurrentMapCacheManager预期会自动配置。如果不是这种情况(您提供了自己的配置或自动配置了不同的缓存提供程序),则根本不会调用自定义程序。您可以拥有任意数量的自定义程序,也可以使用@Order或订购它们Ordered

Generic

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

JCache(JSR-107)

JCache通过javax.cache.spi.CachingProvider类路径上的存在(即类路径上存在符合JSR-107的缓存库)进行引导 ,JCacheCacheManager并由spring-boot-starter-cache“Starter”提供。可以使用各种兼容库,Spring Boot为Ehcache 3,Hazelcast和Infinispan提供依赖管理。还可以添加任何其他兼容库。

可能会出现多个提供程序,在这种情况下,必须明确指定提供程序。即使JSR-107标准没有强制执行定义配置文件位置的标准化方法,Spring Boot也会尽力满足设置缓存的实现细节,如下例所示:

1
2
3
   #仅在存在多个提供程序时才需要
spring.cache.jcache.provider=com.acme.MyCachingProvider
spring.cache.jcache.config=classpath:acme.xml

当缓存库同时提供本机实现和JSR-107支持时,Spring Boot更喜欢JSR-107支持,因此如果切换到不同的JSR-107实现,则可以使用相同的功能。

Spring Boot 对Hazelcast一般支持。如果单个HazelcastInstance可用,则CacheManager除非spring.cache.jcache.config指定了属性,否则它也会自动重复使用 。

有两种方法可以自定义底层javax.cache.cacheManager

  • 可以通过设置spring.cache.cache-names属性在启动时创建缓存。如果定义了自定义javax.cache.configuration.Configurationbean,则会使用它来自定义它们。
  • org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer使用CacheManagerfor完全自定义的引用调用bean 。

如果javax.cache.CacheManager定义了标准bean,它将自动包装在org.springframework.cache.CacheManager抽象所期望的实现中。没有进一步的自定义。

EhCache 2.x

如果ehcache.xml可以在类路径的根目录中找到名为的文件,则使用EhCache 2.x. 如果找到EhCache 2.x,则使用“Starter” EhCacheCacheManager提供的spring-boot-starter-cache引导缓存管理器。还可以提供备用配置文件,如以下示例所示:

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

Hazelcast

Spring Boot 对Hazelcast一般支持。如果a HazelcastInstance已自动配置,则会自动包装在a中 CacheManager

Infinispan

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

1
spring.cache.infinispan.config=infinispan.xml

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

Infinispan在Spring Boot中的支持仅限于嵌入式模式,非常基础。如果你想要更多选项,你应该使用官方的Infinispan Spring Boot启动器。有关更多详细信息,请参阅 Infinispan的文档

Couchbase

如果Couchbase Java客户端和couchbase-spring-cache 实现可用且配置了Couchbase , CouchbaseCacheManager则会自动配置a。也可以通过设置spring.cache.cache-names属性在启动时创建其他缓存。这些缓存在Bucket自动配置的情况下运行。您可以创建另一个附加缓存中Bucket,通过使用定制。假设在“main” 和one()缓存上需要两个缓存(cache1cache2),Bucket并且cache3“另一个”上的自定义时间为2秒Bucket。您可以通过配置创建前两个缓存,如下所示:

1
spring.cache.cache-names=cache1,cache2

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@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通过自动配置创建的配置。

Redis

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

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

默认情况下,会添加一个键前缀,这样,如果两个单独的缓存使用相同的键,则Redis没有重叠键,也不能返回无效值。如果您创建自己的设置,我们强烈建议您启用此设置RedisCacheManager

您可以通过添加RedisCacheConfiguration @Bean自己的配置来完全控制配置。如果您正在寻找自定义序列化策略,这可能很有用。

Caffeine

Caffeine是Java 8重写的Guava缓存,取代了对Guava的支持。如果存在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

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

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

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

Simple

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

1
spring.cache.cache-names=cache1,cache2

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

None

如果@EnableCaching配置中存在,则还需要合适的缓存配置。如果需要在某些环境中完全禁用缓存,请强制缓存类型none使用no-op实现,如以下示例所示:

1
spring.cache.type=none