对于最新稳定版本,请使用Spring Framework 7.0.1spring-doc.cadn.net.cn

基于声明式注释的缓存

对于缓存声明,Spring的缓存抽象提供了一组Java注释:spring-doc.cadn.net.cn

@Cacheable注解

顾名思义,你可以使用@Cacheable用来划分可缓存的方法——即结果存储在缓存中的方法,使得在后续 调用(参数相同),缓存中的值会返回 不得不实际调用这个方法。最简单的形式是注释声明 需要与注释方法关联的缓存名称,具体如下 示例如下:spring-doc.cadn.net.cn

@Cacheable("books")
public Book findBook(ISBN isbn) {...}

在前面的摘录中,findBook方法与名为. 每次调用该方法时,都会检查缓存,看看调用是否具有 已经运行过,无需重复。而在大多数情况下,只有一个 声明缓存后,注释允许指定多个名称,以便多个 缓存正在使用。在这种情况下,每个缓存都会在调用 方法——如果至少触发一个缓存,则返回相应的值。spring-doc.cadn.net.cn

所有不包含该值的其他缓存也会被更新,尽管 缓存方法实际上并未被调用。

以下示例使用@CacheablefindBook多缓存方法:spring-doc.cadn.net.cn

@Cacheable({"books", "isbns"})
public Book findBook(ISBN isbn) {...}

默认密钥生成

由于缓存本质上是键值存储,每次调用缓存方法时 需要被转换为适合缓存访问的密钥。缓存抽象 使用简单的密钥生成器基于以下算法:spring-doc.cadn.net.cn

只要参数具有自然密钥,这种方法在大多数用例中都有效 并实现有效hashCode()等值()方法。如果不是这样, 你需要改变策略。spring-doc.cadn.net.cn

要提供不同的默认密钥生成器,你需要实现org.springframework.cache.interceptor.KeyGenerator接口。spring-doc.cadn.net.cn

默认密钥生成策略随着春季4.0的发布发生了变化。早些时候 Spring的版本采用了密钥生成策略,对于多个关键参数, 仅考虑hashCode()参数的 和 不是等值().这可能导致 意外密钥碰撞(背景见 Spring-Framework#14870)。新的SimpleKeyGenerator对于此类情况,使用复合密钥。spring-doc.cadn.net.cn

如果你想继续使用之前的密钥策略,可以配置已弃用的org.springframework.cache.interceptor.DefaultKeyGenerator类或自定义 基于哈希密钥生成器实现。spring-doc.cadn.net.cn

自定义密钥生成声明

由于缓存是通用的,目标方法很可能会有不同的签名 这无法轻易地映射到缓存结构之上。这一点很容易显而易见 当目标方法有多个参数,其中只有部分参数适合 缓存(其余部分仅由方法逻辑使用)。请考虑以下例子:spring-doc.cadn.net.cn

@Cacheable("books")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

乍一看,当两人布尔论点影响了书籍的呈现方式, 它们对缓存没用。此外,如果两者中只有一个重要呢 而另一个则不在?spring-doc.cadn.net.cn

对于此类情况,@Cacheable注释功能可以让你指定密钥的生成方式 通过其钥匙属性。你可以用SpEL来选择 感兴趣的参数(或其嵌套属性)、执行作,甚至 调用任意方法,无需编写代码或实现任何接口。 这是推荐的替代默认生成器的方法, 因为随着代码库的扩展,方法的签名通常会有很大差异。虽然 默认策略可能适用于某些方法,但很少适用于所有方法。spring-doc.cadn.net.cn

以下示例使用了各种 SpEL 声明(如果你不熟悉 SpEL, 帮自己一个忙,去读读《春季表达语言》):spring-doc.cadn.net.cn

@Cacheable(cacheNames="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

@Cacheable(cacheNames="books", key="#isbn.rawNumber")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

@Cacheable(cacheNames="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

前面的摘录展示了选择某个论元(其中一个)有多容易 属性,甚至是任意(静态)方法。spring-doc.cadn.net.cn

如果负责生成密钥的算法过于具体,或者它需要 为了分享,你可以定义一个自定义keyGenerator关于手术。为此, 指定密钥生成器BEAN 实现用于以下内容 示例如下:spring-doc.cadn.net.cn

@Cacheable(cacheNames="books", keyGenerator="myKeyGenerator")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
钥匙keyGenerator参数互斥且是作 该条件说明了两者都会产生例外。

默认缓存分辨率

缓存抽象使用简单的缓存解析器它会检索缓存 在作层面通过使用配置的缓存管理器.spring-doc.cadn.net.cn

要提供不同的默认缓存解析器,你需要实现org.springframework.cache.interceptor.CacheResolver接口。spring-doc.cadn.net.cn

自定义缓存解析

默认缓存分辨率非常适合与 单缓存管理器并且没有复杂的缓存分辨率要求。spring-doc.cadn.net.cn

对于支持多个缓存管理器的应用程序,你可以设置缓存管理器用于每个作,如下示例所示:spring-doc.cadn.net.cn

@Cacheable(cacheNames="books", cacheManager="anotherCacheManager") (1)
public Book findBook(ISBN isbn) {...}
1 指定anotherCacheManager(另一个缓存管理器).

你也可以替换缓存解析器完全以类似 替换密钥生成。 每次缓存作都会请求解析,以便实现 实际上是基于运行时参数解析缓存来使用。以下示例 展示了如何指定 a缓存解析器:spring-doc.cadn.net.cn

@Cacheable(cacheResolver="runtimeCacheResolver") (1)
public Book findBook(ISBN isbn) {...}
1 具体说明缓存解析器.

自4.1春季以来,缓存注释的属性不再是 必须,因为这些特定信息可以通过缓存解析器无论注释内容如何。spring-doc.cadn.net.cn

类似于钥匙keyGenerator缓存管理器缓存解析器参数互斥,且指定两者皆存在的作 结果是例外,作为一种习惯缓存管理器被 忽略缓存解析器实现。这大概不是你所期待的。spring-doc.cadn.net.cn

同步缓存

在多线程环境中,某些作可能会同时调用 同样的论点(通常是在启动时)。默认情况下,缓存抽象并不支持 锁定任何东西,且相同的值可能会被多次计算,从而破坏初度 关于缓存。spring-doc.cadn.net.cn

对于这些特定情况,你可以使用同步属性来指示底层 缓存提供者在计算值时锁定缓存条目。因此, 只有一个线程忙于计算该值,其他线程则被阻塞直到条目 在缓存中更新。以下示例展示了如何使用同步属性:spring-doc.cadn.net.cn

@Cacheable(cacheNames="foos", sync=true) (1)
public Foo executeExpensiveOperation(String id) {...}
1 使用同步属性。
这是可选功能,你喜欢的缓存库可能不支持。 都缓存管理器核心框架提供的实现支持该技术。参见 需要查看缓存提供商的文档以获取更多细节。

使用CompletableFuture和Reactive Return类型缓存

截至6.1版本,缓存注释为完成未来以及响应式回流类型 考虑到,自动调整缓存交互。spring-doc.cadn.net.cn

对于返回完成未来,由该未来产生的对象 缓存完成时 会被缓存,缓存命中时的缓存查找也会 通过完成未来:spring-doc.cadn.net.cn

@Cacheable("books")
public CompletableFuture<Book> findBook(ISBN isbn) {...}

对于返回反应堆的方法,即该反应流发射的对象 发布者会在可用时缓存,缓存查询 命中将被检索为(由完成未来):spring-doc.cadn.net.cn

@Cacheable("books")
public Mono<Book> findBook(ISBN isbn) {...}

对于返回反应堆的方法通量,即由该反应流发射的对象 出版商将被收集到一个列表并且在该列表完成时缓存, 缓存查询将以通量(由完成未来对于缓存的列表价值):spring-doc.cadn.net.cn

@Cacheable("books")
public Flux<Book> findBooks(String author) {...}

这样完成未来响应式适应也适用于同步缓存, 在同时缓存未命中时只计算一次该值:spring-doc.cadn.net.cn

@Cacheable(cacheNames="foos", sync=true) (1)
public CompletableFuture<Foo> executeExpensiveOperation(String id) {...}
1 使用同步属性。
为了让这种安排在运行时正常工作,配置好的缓存 需要具备完成未来基于检索。泉水提供的ConcurrentMapCacheManager自动适应这种检索方式,CaffeineCacheManager当其异步缓存模式为 启用:设置setAsyncCacheMode(true)在你的CaffeineCacheManager实例。
@Bean
CacheManager cacheManager() {
	CaffeineCacheManager cacheManager = new CaffeineCacheManager();
	cacheManager.setCacheSpecification(...);
	cacheManager.setAsyncCacheMode(true);
	return cacheManager;
}

最后但同样重要的是,要注意注释驱动的缓存并不合适 用于涉及成分和背压的复杂反应性相互作用。 如果你选择申报@Cacheable在特定的响应式方法上,考虑 较粗粒度缓存交互的影响,该相互作用仅存储 对于 a 的发射对象甚至是预先收集的对象列表通量.spring-doc.cadn.net.cn

条件缓存

有时,某种方法可能不适合一直缓存(例如,可能 取决于给定的论证)。缓存注释通过条件参数,该参数取一个SpEL被评估为以下truefalse.如果true,方法被缓存。如果不是,则表现为方法本身不存在 缓存(即无论缓存中值如何,每次都会调用该方法) 或者使用了哪些论证)。例如,以下方法只有在 论点名称长度短于32:spring-doc.cadn.net.cn

@Cacheable(cacheNames="book", condition="#name.length() < 32") (1)
public Book findBook(String name)
1 在 上设置条件@Cacheable.

此外条件参数,你可以使用除非否决 的参数 向缓存添加一个值。与条件,除非表达式被评估 在方法被调用之后。扩展到前面的例子,也许我们只是 想要缓存平装书,正如以下例子所示:spring-doc.cadn.net.cn

@Cacheable(cacheNames="book", condition="#name.length() < 32", unless="#result.hardback") (1)
public Book findBook(String name)
1 使用除非归于硬壳方块。

缓存抽象支持java.util.Optional返回类型。如果自选价值 存在,它会被存储在关联的缓存中。如果自选价值不是 目前将存储在关联的缓存中。#result总是指 商业实体,且从未被支持封装,因此之前的示例可以重写 如下:spring-doc.cadn.net.cn

@Cacheable(cacheNames="book", condition="#name.length() < 32", unless="#result?.hardback")
public Optional<Book> findBook(String name)

注意#result仍然指可选<书>.因为可能是我们使用 SpEL 的安全导航操作员spring-doc.cadn.net.cn

可用的缓存 SpEL 评估上下文

SpEL表达式对专用上下文. 除了内置参数外,该框架还提供专用的缓存相关功能 元数据,比如参数名称。下表描述了制作的物品 上下文中可用,以便你用它们进行密钥和条件计算:spring-doc.cadn.net.cn

表1。SpEL表达式中的缓存元数据
名称 位置 描述 示例

方法名称spring-doc.cadn.net.cn

根对象spring-doc.cadn.net.cn

被引用的方法名称spring-doc.cadn.net.cn

#root.methodNamespring-doc.cadn.net.cn

方法spring-doc.cadn.net.cn

根对象spring-doc.cadn.net.cn

所引用的方法spring-doc.cadn.net.cn

#root.method.namespring-doc.cadn.net.cn

目标spring-doc.cadn.net.cn

根对象spring-doc.cadn.net.cn

被调用的目标对象spring-doc.cadn.net.cn

#root.targetspring-doc.cadn.net.cn

目标类spring-doc.cadn.net.cn

根对象spring-doc.cadn.net.cn

被调用的目标类别spring-doc.cadn.net.cn

#root.targetClassspring-doc.cadn.net.cn

argsspring-doc.cadn.net.cn

根对象spring-doc.cadn.net.cn

用于调用目标的参数(作为对象数组)spring-doc.cadn.net.cn

#root.args[0]spring-doc.cadn.net.cn

缓存spring-doc.cadn.net.cn

根对象spring-doc.cadn.net.cn

当前方法运行的缓存集合spring-doc.cadn.net.cn

#root.caches[0].namespring-doc.cadn.net.cn

论元名称spring-doc.cadn.net.cn

评估背景spring-doc.cadn.net.cn

某个特定方法论元的名称。如果名字不可得 (例如,因为代码编译时没有-参数旗帜),个人 参数也可用#a<#arg>语法 其中<#arg>代表 论元索引(从0开始)。spring-doc.cadn.net.cn

#iban#a0(你也可以使用#p0#p<#arg>作为别名的符号)。spring-doc.cadn.net.cn

结果spring-doc.cadn.net.cn

评估背景spring-doc.cadn.net.cn

方法调用的结果(要缓存的值)。仅有除非表达 式缓存放置表达式(用于计算钥匙),或缓存驱逐表达式(当祈祷之前false).对于支持的包装器(例如自选),#result指的是实际的对象,而不是包裹体。spring-doc.cadn.net.cn

#resultspring-doc.cadn.net.cn

@CachePut注解

当缓存需要在不干扰方法执行的情况下更新时, 你可以使用@CachePut注解。也就是说,该方法总是被调用,并且其 结果被放入缓存中(根据@CachePut选项)。它支持 与@Cacheable应用于缓存填充,而非 方法流程优化。以下示例使用了@CachePut注解:spring-doc.cadn.net.cn

@CachePut(cacheNames="book", key="#isbn")
public Book updateBook(ISBN isbn, BookDescriptor descriptor)
@CachePut@Cacheable同一方法的注释通常为 强烈不鼓励,因为它们的行为不同。而后者则导致 如果要通过使用缓存跳过方法调用,前者强制调用 命令执行缓存更新。这导致了意外的行为,除了 特定角落情况的说明(例如具有排除这些条件的注释 其他),应避免此类声明。还要注意,这些条件不应依赖 对结果对象(即#result变量),因为这些在前被验证为 确认排除。

截至6.1,@CachePut需要完成未来以及考虑响应式回报类型, 只要产生了对象可用,就执行该作。spring-doc.cadn.net.cn

@CacheEvict注解

缓存抽象不仅允许缓存存储的填充,还支持逐出。 该过程有助于从缓存中移除过时或未使用的数据。相对于@Cacheable,@CacheEvict标记执行缓存的方法 驱逐(即作为触发器从缓存中移除数据的方法)。 与其兄弟类似,@CacheEvict需要指定一个或多个缓存 受动作影响的,允许自定义缓存和密钥解析,或 条件需指定,并具有一个额外的参数 (所有参赛作品)指示是否需要执行全缓存驱逐 而不是仅仅基于钥匙的进入淘汰。以下示例驱逐 所有来自缓存:spring-doc.cadn.net.cn

@CacheEvict(cacheNames="books", allEntries=true) (1)
public void loadBooks(InputStream batch)
1 使用所有参赛作品属性 以驱逐缓存中的所有条目。

当需要清理整个缓存区域时,这个选项非常有用。 与其逐条逐条逐项淘汰(那样效率低,耗时很长), 所有元素在一次作中被移除,如前例所示。 请注意,框架在此场景中忽略了指定的任何密钥,因为该密钥不适用 (整个缓存被淘汰,而不仅仅是一个条目。)spring-doc.cadn.net.cn

你也可以说明驱逐是在默认之后还是之前进行 该方法通过使用祈祷之前属性。前者提供了 与其他注释的语义相同:一旦方法成功完成, 对缓存执行一个作(此处为驱逐)。如果方法不成立 运行(因为可能被缓存)或抛出异常,则不会发生驱逐。 后者(beforeInvocation=真导致驱逐总是发生在 方法被调用。这在驱逐不需要打平的情况下非常有用 对方法结果的判断。spring-doc.cadn.net.cn

注意无效方法可用于@CacheEvict- 因为方法的作用是 触发时,返回值被忽略(因为它们不与缓存交互)。这是 但与@Cacheable这会向缓存中添加数据或更新缓存中的数据 因此,需要一个结果。spring-doc.cadn.net.cn

截至6.1,@CacheEvict需要完成未来以及考虑响应式回报类型, 每当处理完成后执行一次调用后的驱逐作。spring-doc.cadn.net.cn

@Caching注解

有时,同一类型的多个注释(例如@CacheEvict@CachePut需要指定 — 例如,因为条件 或 键 不同缓存的表达方式不同。@Caching让多重嵌套@Cacheable,@CachePut@CacheEvict注释也适用于相同的方法。 以下示例使用了两个@CacheEvict附注:spring-doc.cadn.net.cn

@Caching(evict = { @CacheEvict("primary"), @CacheEvict(cacheNames="secondary", key="#p0") })
public Book importBooks(String deposit, Date date)

@CacheConfig注解

到目前为止,我们看到缓存作提供了许多自定义选项,并且 你可以为每个作设置这些选项。不过,有些自定义选项 如果这些作适用于类的所有作,配置起来可能会很繁琐。为 实例,指定每个缓存作中所用的缓存名称 类可以被单一的类级定义替代。这里是@CacheConfig这就开始发挥作用了。以下示例使用@CacheConfig设置缓存名称:spring-doc.cadn.net.cn

@CacheConfig("books") (1)
public class BookRepositoryImpl implements BookRepository {

	@Cacheable
	public Book findBook(ISBN isbn) {...}
}
1 @CacheConfig来设置缓存的名称。

@CacheConfig是一种类级注释,允许共享缓存名称, 习俗密钥生成器,习俗缓存管理器,以及惯例缓存解析器. 在类上放置该注释不会启动任何缓存作。spring-doc.cadn.net.cn

作级自定义总是覆盖 的自定义集@CacheConfig. 因此,每个缓存作可进行三层自定义:spring-doc.cadn.net.cn

通常提供服务提供者特定的设置缓存管理器豆 例如,在CaffeineCacheManager.这些实际上也是全球性的。

启用缓存注释

需要注意的是,尽管声明缓存注释并不意味着 自动触发他们的动作——像春季的许多功能一样,这个功能必须是 声明式启用(这意味着如果你怀疑缓存是原因,可以 只需移除一行配置,而不是移除所有注释,即可禁用它 你的代码)。spring-doc.cadn.net.cn

要启用缓存注释,请添加注释@EnableCaching给你的其中一位@Configuration类:spring-doc.cadn.net.cn

@Configuration
@EnableCaching
class AppConfig {

	@Bean
	CacheManager cacheManager() {
		CaffeineCacheManager cacheManager = new CaffeineCacheManager();
		cacheManager.setCacheSpecification(...);
		return cacheManager;
	}
}

另外,对于XML配置,你可以使用缓存:注释驱动元素:spring-doc.cadn.net.cn

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:cache="http://www.springframework.org/schema/cache"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/cache https://www.springframework.org/schema/cache/spring-cache.xsd">

	<cache:annotation-driven/>

	<bean id="cacheManager" class="org.springframework.cache.caffeine.CaffeineCacheManager">
		<property name="cacheSpecification" value="..."/>
	</bean>
</beans>

两者缓存:注释驱动元素和@EnableCaching注释可以让你 指定各种影响缓存行为添加方式的选项 通过AOP申请。该构型有意与@Transactional.spring-doc.cadn.net.cn

处理缓存注释的默认建议模式为代理,这使得 仅用于通过代理拦截通话。同一类内的本地呼叫 不能被拦截。对于更高级的截获模式,考虑 切换至Aspectj模式与编译时或加载时织入结合。
关于高级定制(使用Java配置)的更多细节,以下内容包括 实施的必要条件缓存配置器,请参见Javadoc
表2。缓存注释设置
XML属性 注释属性 默认值 描述

缓存管理器spring-doc.cadn.net.cn

不适用(参见缓存配置器Javadoc)spring-doc.cadn.net.cn

缓存管理器spring-doc.cadn.net.cn

缓存管理器的名称。默认缓存解析器初始化在后方 使用该缓存管理器(或缓存管理器如果未设置)。更多内容 缓存解析的细粒度管理,考虑设置“缓存解析器” 属性。spring-doc.cadn.net.cn

缓存解析器spring-doc.cadn.net.cn

不适用(参见缓存配置器Javadoc)spring-doc.cadn.net.cn

一个SimpleCacheResolver使用 配置缓存管理器.spring-doc.cadn.net.cn

用于解析后备缓存的缓存解析器的豆名。 该属性并非必需,只需作为替代方案指定 即“缓存管理器”属性。spring-doc.cadn.net.cn

密钥生成器spring-doc.cadn.net.cn

不适用(参见缓存配置器Javadoc)spring-doc.cadn.net.cn

SimpleKeyGeneratorspring-doc.cadn.net.cn

自定义密钥生成器的名称。spring-doc.cadn.net.cn

错误处理spring-doc.cadn.net.cn

不适用(参见缓存配置器Javadoc)spring-doc.cadn.net.cn

SimpleCacheErrorHandlerspring-doc.cadn.net.cn

自定义缓存错误处理程序的名称。默认情况下,任何在 缓存相关的作会被抛回客户端。spring-doc.cadn.net.cn

模式spring-doc.cadn.net.cn

模式spring-doc.cadn.net.cn

代理spring-doc.cadn.net.cn

默认模式(代理)通过使用 Spring 的 AOP 处理注释豆子以便代理 框架(遵循代理语义,如前所述,应用于方法调用 只能通过代理进入)。替代模式(Aspectj) 反而编织出 受影响的类带有 Spring 的 AspectJ 缓存特性,修改目标类字节 代码可以应用于任何类型的方法调用。AspectJ 编织需要spring-aspects.jar在类路径中,并且启用了加载时编织(或编译时编织)。(有关如何设置的详细信息,请参见Spring配置 加载时编织。)spring-doc.cadn.net.cn

代理目标类spring-doc.cadn.net.cn

proxyTargetClassspring-doc.cadn.net.cn

falsespring-doc.cadn.net.cn

仅适用于代理模式。控制为何种类型的缓存代理创建 用@Cacheable@CacheEvict附注。如果代理目标类属性设置为true创建基于类的代理。 如果代理目标类false或者如果省略了该属性,则使用标准的JDK 基于接口的代理被创建。(有关不同代理类型的详细考察,请参见代理机制。)spring-doc.cadn.net.cn

次序spring-doc.cadn.net.cn

次序spring-doc.cadn.net.cn

Ordered.LOWEST_PRECEDENCEspring-doc.cadn.net.cn

定义了对注释为 的豆子应用缓存建议的顺序@Cacheable@CacheEvict.(关于相关规则的更多信息 订购AOP建议,详见“建议订购”。) 没有指定的排序意味着AOP子系统决定了建议的顺序。spring-doc.cadn.net.cn

<缓存:注释驱动/>寻找@Cacheable/@CachePut/@CacheEvict/@Caching仅限于定义的同一应用上下文中的豆子。这意味着, 如果你放<缓存:注释驱动/>WebApplicationContext对于调度器服务它只检查你的控制器中的豆子,而不是你的服务。 更多信息请参见MVC部分
方法可视化与缓存注释

使用代理时,缓存注释应仅应用于 公众可见度。如果你要注释保护、私有或包可见的方法 使用这些注释时,不会产生错误,但注释方法不会表现出 配置好的缓存设置。考虑使用AspectJ(详见本节剩余部分) 如果你需要注释非公开方法,因为它会改变字节码本身。spring-doc.cadn.net.cn

Spring建议你只注释具体类(以及具体类的方法) 类)中@Cache*注释,而不是注释接口。 你当然可以设置@Cache*接口上的注释(或接口) 方法),但这只在你使用代理模式时才有效(mode=“代理”).如果你使用了 基于织造的方面(mode=“aspectj”),缓存设置在 上无法识别 由织造基础设施进行接口级声明。
在代理模式(默认情况下),只有外部方法调用通过 代理被截获。这意味着自调用(实际上是 调用目标对象的另一个方法)不会导致实际 即使调用的方法标记为@Cacheable.考虑 使用Aspectj在这种情况下,模式。此外,代理必须完全初始化为 提供预期的行为,因此你不应依赖此功能 初始化代码(即,@PostConstruct).

使用自定义注释

自定义注释与 AspectJ

此功能仅适用于基于代理的方法,但可以启用 通过使用AspectJ,稍微多花点功夫。spring-doc.cadn.net.cn

Spring方面模块仅定义标准注释的体。 如果你已经定义了自己的注释,你还需要定义一个 那些。检查注释缓存方面举个例子。spring-doc.cadn.net.cn

缓存抽象允许你用自己的注释来识别该采用的方法 触发缓存人口或驱逐。这作为模板机制非常实用, 因为它消除了重复缓存注释声明的需求,即 尤其适用于指定密钥或条件,或外国进口 (org.springframework)不允许出现在你的代码库中。和其他人类似 在刻板印象注释中,你可以 用@Cacheable,@CachePut,@CacheEvict@CacheConfig作为元注释(即 可以注释其他注释)。在以下例子中,我们替换一个公用@Cacheable声明,附有我们自定义注释:spring-doc.cadn.net.cn

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Cacheable(cacheNames="books", key="#isbn")
public @interface SlowService {
}

在前面的例子中,我们定义了自己的慢速服务注解 该符号本身被注释为@Cacheable.现在我们可以替换以下代码:spring-doc.cadn.net.cn

@Cacheable(cacheNames="books", key="#isbn")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

以下示例展示了我们可以用来替换 前置代码:spring-doc.cadn.net.cn

@SlowService
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)

即使@SlowService不是 Spring 注释,容器会自动选择 运行时要理解它的声明并理解它的含义。注意,如前所述,需要启用注释驱动的行为。spring-doc.cadn.net.cn