此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10spring-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方法与名为books. 每次调用该方法时,都会检查缓存以查看调用是否具有 已经运行,不必重复。而在大多数情况下,只有一个 cache 声明时,注释允许指定多个名称,以便多个 缓存正在使用中。在这种情况下,在调用 method — 如果至少命中一个缓存,则返回关联值。spring-doc.cadn.net.cn

所有其他不包含该值的缓存也会更新,即使 缓存方法实际上没有被调用。

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

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

默认密钥生成

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

这种方法适用于大多数用例,只要参数具有自然键 并实现有效的hashCode()equals()方法。如果不是这样, 你需要改变策略。spring-doc.cadn.net.cn

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

默认密钥生成策略随着 Spring 4.0 的发布而更改。早些时候 Spring 版本使用密钥生成策略,对于多个密钥参数, 仅考虑hashCode()参数而不是equals().这可能会导致 意外的键冲突(有关背景,请参阅 spring-framework#14870)。新的SimpleKeyGenerator对于此类方案使用复合键。spring-doc.cadn.net.cn

如果要继续使用以前的关键策略,可以配置已弃用的org.springframework.cache.interceptor.DefaultKeyGenerator类或创建自定义 基于哈希KeyGenerator实现。spring-doc.cadn.net.cn

自定义密钥生成声明

由于缓存是通用的,因此目标方法很可能具有各种签名 不能轻易映射到缓存结构之上。这往往会变得显而易见 当目标方法有多个参数,其中只有一些参数适合 缓存(而其余的仅由方法逻辑使用)。请考虑以下示例:spring-doc.cadn.net.cn

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

乍一看,虽然两人boolean论点会影响这本书的发现方式, 它们对缓存没有用处。此外,如果两者中只有一个很重要怎么办 而另一个则不是?spring-doc.cadn.net.cn

对于此类情况,@Cacheable注释允许您指定键的生成方式 通过其key属性。您可以使用 SpEL 来拾取 感兴趣的参数(或其嵌套属性)、执行作,甚至 调用任意方法,无需编写任何代码或实现任何接口。 这是默认生成器的推荐方法 因为随着代码库的增长,方法在签名中往往会大不相同。虽然 默认策略可能适用于某些方法,但很少适用于所有方法。spring-doc.cadn.net.cn

以下示例使用各种 SpEL 声明(如果您不熟悉 SpEL, 帮自己一个忙,阅读 Spring Expression Language):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在作上。为此, 指定KeyGeneratorbean 实现,如下所示 示例显示:spring-doc.cadn.net.cn

@Cacheable(cacheNames="books", keyGenerator="myKeyGenerator")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
keykeyGenerator参数互斥且为作 指定两者都会导致异常。

默认缓存解析

缓存抽象使用简单的CacheResolver检索缓存 使用配置的CacheManager.spring-doc.cadn.net.cn

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

自定义缓存解析

默认缓存分辨率非常适合使用 单CacheManager并且没有复杂的缓存解析要求。spring-doc.cadn.net.cn

对于使用多个缓存管理器的应用程序,您可以将cacheManager用于每个作,如以下示例所示:spring-doc.cadn.net.cn

@Cacheable(cacheNames="books", cacheManager="anotherCacheManager") (1)
public Book findBook(ISBN isbn) {...}
1 指定anotherCacheManager.

您还可以将CacheResolver完全以类似于 替换密钥生成。 每个缓存作都会请求解析,让实现 实际上,根据运行时参数解析要使用的缓存。以下示例 演示了如何指定CacheResolver:spring-doc.cadn.net.cn

@Cacheable(cacheResolver="runtimeCacheResolver") (1)
public Book findBook(ISBN isbn) {...}
1 指定CacheResolver.

从 Spring 4.1 开始,value缓存注释的属性不再 强制的,因为此特定信息可以由CacheResolver无论注释的内容如何。spring-doc.cadn.net.cn

类似于keykeyGeneratorcacheManagercacheResolver参数是互斥的,并且指定两者的作 导致异常,作为自定义CacheManagerCacheResolver实现。这可能不是你所期望的。spring-doc.cadn.net.cn

同步缓存

在多线程环境中,某些作可能会同时调用 相同的参数(通常在启动时)。默认情况下,缓存抽象不会 锁定任何东西,并且相同的值可能会被多次计算,从而违背了目的 缓存。spring-doc.cadn.net.cn

对于这些特定情况,您可以使用sync属性来指示底层 cache 提供程序,用于在计算值时锁定缓存条目。结果, 只有一个线程忙于计算值,而其他线程则被阻塞,直到条目 在缓存中更新。以下示例演示如何使用sync属性:spring-doc.cadn.net.cn

@Cacheable(cacheNames="foos", sync=true) (1)
public Foo executeExpensiveOperation(String id) {...}
1 使用sync属性。
这是一项可选功能,您最喜欢的缓存库可能不支持它。 都CacheManager核心框架提供的实现支持 IT。请参阅 有关更多详细信息,请参阅缓存提供程序的文档。

使用 CompletableFuture 和响应式返回类型进行缓存

从 6.1 开始,缓存注释需要CompletableFuture和响应式返回类型 考虑,相应地自动调整缓存交互。spring-doc.cadn.net.cn

对于返回CompletableFuture,该未来产生的对象 将在完成时缓存,并且缓存命中的缓存查找将 通过CompletableFuture:spring-doc.cadn.net.cn

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

对于返回 Reactor 的方法Mono,则该响应式流发出的对象 只要发布者可用,就会被缓存,缓存查找缓存 hit 将作为Mono(由CompletableFuture):spring-doc.cadn.net.cn

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

对于返回 Reactor 的方法Flux,则该响应式流发出的对象 publisher 将被收集到List并在该列表完成时缓存, 缓存命中的缓存查找将作为Flux(由CompletableFuture对于缓存的List值):spring-doc.cadn.net.cn

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

这样CompletableFuture响应式适应也适用于同步缓存, 在并发缓存未命中的情况下仅计算一次值:spring-doc.cadn.net.cn

@Cacheable(cacheNames="foos", sync=true) (1)
public CompletableFuture<Foo> executeExpensiveOperation(String id) {...}
1 使用sync属性。
为了使这种安排在运行时工作,配置的缓存 需要能够CompletableFuture基于检索。泉水提供的ConcurrentMapCacheManager自动适应该检索样式,并且CaffeineCacheManager当其异步缓存模式为 enabled:设置setAsyncCacheMode(true)在您的CaffeineCacheManager实例。
@Bean
CacheManager cacheManager() {
	CaffeineCacheManager cacheManager = new CaffeineCacheManager();
	cacheManager.setCacheSpecification(...);
	cacheManager.setAsyncCacheMode(true);
	return cacheManager;
}

最后但并非最不重要的一点是,请注意注释驱动的缓存是不合适的 用于涉及成分和背压的复杂反应性相互作用。 如果您选择声明@Cacheable在特定的响应式方法上,考虑 相当粗粒度的缓存交互的影响,该交互只是将 emitted 对象的Mono甚至是预先收集的对象列表Flux.spring-doc.cadn.net.cn

条件缓存

有时,一个方法可能并不适合始终缓存(例如,它可能 取决于给定的参数)。缓存注释通过condition参数,它采用SpEL计算结果为truefalse.如果true,则该方法被缓存。如果不是,它的行为就好像该方法不是 cached(即,无论缓存中是什么值,每次都会调用该方法 或使用什么参数)。例如,仅当 论点name长度短于 32:spring-doc.cadn.net.cn

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

除了condition参数,您可以使用unless参数来否决 向缓存添加值。与condition,unless表达式被计算 在调用该方法之后。为了扩展前面的例子,也许我们只是 想要缓存平装书,如以下示例所示:spring-doc.cadn.net.cn

@Cacheable(cacheNames="book", condition="#name.length() < 32", unless="#result.hardback") (1)
public Book findBook(String name)
1 使用unless属性来阻止精装本。

缓存抽象支持java.util.Optional返回类型。如果Optional价值 存在,它将存储在关联的缓存中。如果Optional值不是 目前null将存储在关联的缓存中。#result总是引用业务实体,而不是受支持的包装器,因此可以重写前面的示例 如下:spring-doc.cadn.net.cn

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

请注意#resultstill 指的是Book而不是Optional<Book>. 既然可能是null,我们使用 SpEL 的安全导航运算符spring-doc.cadn.net.cn

可用的缓存 SpEL 评估上下文

SpELexpression 根据专用的context. 除了内置参数外,框架还提供了与缓存相关的专用参数 元数据,例如参数名称。下表描述了制作的项目 可用于上下文,以便您可以将它们用于键和条件计算:spring-doc.cadn.net.cn

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

methodNamespring-doc.cadn.net.cn

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

正在调用的方法的名称spring-doc.cadn.net.cn

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

methodspring-doc.cadn.net.cn

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

正在调用的方法spring-doc.cadn.net.cn

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

targetspring-doc.cadn.net.cn

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

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

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

targetClassspring-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

cachesspring-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

特定方法参数的名称。如果名称不可用 (例如,因为代码是在没有-parametersflag)、个人 参数也可以使用#a<#arg>语法,其中<#arg>代表 参数索引(从 0 开始)。spring-doc.cadn.net.cn

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

resultspring-doc.cadn.net.cn

评估上下文spring-doc.cadn.net.cn

方法调用的结果(要缓存的值)。仅适用于unless表达 式cache put表达式(以计算key),或cache evict表达式(当beforeInvocationfalse).对于受支持的包装器(例如Optional),#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需要CompletableFuture和响应式返回类型考虑在内, 每当生成的对象可用时执行放置作。spring-doc.cadn.net.cn

@CacheEvict注解

缓存抽象不仅允许填充缓存存储,还允许驱逐。 此过程对于从缓存中删除过时或未使用的数据非常有用。与@Cacheable,@CacheEvict分界执行缓存的方法 逐出(即充当从缓存中删除数据的触发器的方法)。 与它的兄弟姐妹类似,@CacheEvict需要指定一个或多个缓存 ,允许自定义缓存和密钥解析或 条件,并具有额外的参数 (allEntries),指示是否需要执行缓存范围的逐出 而不仅仅是条目驱逐(基于密钥)。以下示例将 来自books缓存:spring-doc.cadn.net.cn

@CacheEvict(cacheNames="books", allEntries=true) (1)
public void loadBooks(InputStream batch)
1 使用allEntries属性从缓存中逐出所有条目。

当需要清除整个缓存区域时,此选项会派上用场。 与其逐出每个条目(这将花费很长时间,因为它效率低下), 所有条目都将在一次作中删除,如前面的示例所示。 请注意,框架会忽略此方案中指定的任何键,因为它不适用 (逐出整个缓存,而不仅仅是一个条目)。spring-doc.cadn.net.cn

您还可以指示逐出是在(默认值)之后还是之前进行 该方法是使用beforeInvocation属性。前者提供了 与其他注释相同的语义:方法成功完成后, 对缓存运行作(在本例中为逐出)。如果方法没有 run(因为它可能被缓存)或引发异常,则不会发生逐出。 后者 (beforeInvocation=true) 会导致逐出始终发生在 方法被调用。这在不需要绑定驱逐的情况下很有用 到方法结果。spring-doc.cadn.net.cn

请注意void方法可以与@CacheEvict- 由于这些方法充当 trigger,则返回值将被忽略(因为它们不与缓存交互)。这是 不是这样@Cacheable将数据添加到缓存或更新缓存中的数据 因此,需要一个结果。spring-doc.cadn.net.cn

从 6.1 开始,@CacheEvict需要CompletableFuture和响应式返回类型考虑在内, 每当处理完成时执行调用后逐出作。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注解

到目前为止,我们已经看到缓存作提供了许多自定义选项,并且 您可以为每个作设置这些选项。但是,一些自定义选项 如果它们适用于类的所有作,则配置起来可能会很乏味。为 实例,指定要用于 class 可以替换为单个类级定义。这是哪里@CacheConfig发挥作用。以下示例使用@CacheConfig要设置缓存的名称,请执行以下作:spring-doc.cadn.net.cn

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

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

@CacheConfig是一个类级注释,允许共享缓存名称, 自定义KeyGenerator,自定义CacheManager,而自定义CacheResolver. 将此注释放在类上不会打开任何缓存作。spring-doc.cadn.net.cn

作级自定义始终覆盖@CacheConfig. 因此,这为每个缓存作提供了三个级别的自定义:spring-doc.cadn.net.cn

特定于提供程序的设置通常在CacheManager豆 例如,在CaffeineCacheManager.这些实际上也是全球性的。

启用缓存注释

重要的是要注意,即使声明缓存注释不会 自动触发他们的作 - 就像 Spring 中的许多东西一样,该功能必须是 声明性启用(这意味着如果您怀疑缓存是罪魁祸首,您可以 通过仅删除一个配置行而不是 您的代码)。spring-doc.cadn.net.cn

要启用缓存注释,请添加注释@EnableCaching给你的一个@Configuration类或使用cache:annotation-driven元素与 XML 的:spring-doc.cadn.net.cn

@Configuration
@EnableCaching
class CacheConfiguration {

	@Bean
	CacheManager cacheManager() {
		CaffeineCacheManager cacheManager = new CaffeineCacheManager();
		cacheManager.setCacheSpecification("...");
		return cacheManager;
	}
}
@Configuration
@EnableCaching
class CacheConfiguration {

	@Bean
	fun cacheManager(): CacheManager {
		return CaffeineCacheManager().apply {
			setCacheSpecification("...")
		}
	}
}
<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>

两个cache:annotation-driven元素和@EnableCaching注释可以让您 指定影响缓存行为添加到 通过AOP申请。该配置有意与@Transactional.spring-doc.cadn.net.cn

处理缓存注释的默认通知模式为proxy,这允许 仅用于通过代理拦截呼叫。同一类中的本地调用 不能以这种方式被拦截。对于更高级的拦截模式,请考虑 切换到aspectj模式与编译时或加载时编织相结合。
有关高级自定义(使用 Java 配置)的更多详细信息,这些自定义是 需要实现CachingConfigurer,请参阅 javadoc
表 2.缓存注释设置
XML 属性 注释属性 默认值 描述

cache-managerspring-doc.cadn.net.cn

不适用(参见CachingConfigurerjavadoc)spring-doc.cadn.net.cn

cacheManagerspring-doc.cadn.net.cn

要使用的缓存管理器的名称。默认CacheResolver在后面初始化 具有此缓存管理器(或cacheManager如果未设置)。更多 缓存解析的细粒度管理,考虑设置“cache-resolver” 属性。spring-doc.cadn.net.cn

cache-resolverspring-doc.cadn.net.cn

不适用(参见CachingConfigurerjavadoc)spring-doc.cadn.net.cn

一个SimpleCacheResolver使用配置的cacheManager.spring-doc.cadn.net.cn

用于解析后备缓存的 CacheResolver 的 Bean 名称。 此属性不是必需的,只需指定为 'cache-manager' 属性。spring-doc.cadn.net.cn

key-generatorspring-doc.cadn.net.cn

不适用(参见CachingConfigurerjavadoc)spring-doc.cadn.net.cn

SimpleKeyGeneratorspring-doc.cadn.net.cn

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

error-handlerspring-doc.cadn.net.cn

不适用(参见CachingConfigurerjavadoc)spring-doc.cadn.net.cn

SimpleCacheErrorHandlerspring-doc.cadn.net.cn

要使用的自定义缓存错误处理程序的名称。默认情况下,在 缓存相关作将引回客户端。spring-doc.cadn.net.cn

modespring-doc.cadn.net.cn

modespring-doc.cadn.net.cn

proxyspring-doc.cadn.net.cn

默认模式 (proxy)处理使用 Spring 的 AOP 进行代理的带注释的 bean 框架(遵循代理语义,如前所述,应用于方法调用 仅通过代理进入)。替代模式 (aspectj) 改为编织 受影响的类使用 Spring 的 AspectJ 缓存方面,修改目标类字节 应用于任何类型的方法调用的代码。AspectJ 编织需要spring-aspects.jar以及启用加载时编织(或编译时编织)。(有关如何设置的详细信息,请参阅 Spring 配置 加载时间编织。spring-doc.cadn.net.cn

proxy-target-classspring-doc.cadn.net.cn

proxyTargetClassspring-doc.cadn.net.cn

falsespring-doc.cadn.net.cn

仅适用于代理模式。控制为其创建缓存代理的类型 类的@Cacheable@CacheEvict附注。如果proxy-target-class属性设置为true,创建基于类的代理。 如果proxy-target-classfalse或者如果省略了该属性,则标准 JDK 创建基于接口的代理。(有关不同代理类型的详细检查,请参阅代理机制。spring-doc.cadn.net.cn

orderspring-doc.cadn.net.cn

orderspring-doc.cadn.net.cn

Ordered.LOWEST_PRECEDENCEspring-doc.cadn.net.cn

定义应用于标注的 bean 的缓存通知的顺序@Cacheable@CacheEvict.(有关相关规则的更多信息 订购 AOP 通知,请参阅通知订购。 没有指定的排序意味着 AOP 子系统确定通知的顺序。spring-doc.cadn.net.cn

<cache:annotation-driven/>寻找@Cacheable/@CachePut/@CacheEvict/@Caching仅在定义它的同一应用程序上下文中的 bean 上。这意味着, 如果你把<cache:annotation-driven/>WebApplicationContext对于一个DispatcherServlet,它只检查控制器中的 Bean,而不是服务中的 Bean。 有关详细信息,请参阅 MVC 部分
方法可见性和缓存注释

使用代理时,应仅将缓存注释应用于具有 公众可见性。如果您确实注释了受保护、私有或包可见的方法 使用这些注释时,不会引发错误,但带注释的方法不会显示 配置的缓存设置。考虑使用 AspectJ(请参阅本节的其余部分) 如果您需要注释非公共方法,因为它会更改字节码本身。spring-doc.cadn.net.cn

Spring 建议您只注释具体类(以及具体 类)替换为@Cache*注释,而不是注释接口。 你当然可以放置一个@Cache*接口(或接口 方法),但这仅在您使用代理模式(mode="proxy").如果您使用 基于编织的方面 (mode="aspectj"),缓存设置在 接口级声明。
在代理模式(默认)中,只有通过 代理被拦截。这意味着自调用(实际上,在 target 对象调用 target 对象的另一个方法)不会导致实际的 运行时缓存,即使调用的方法标记为@Cacheable.考虑 使用aspectj在这种情况下,模式。此外,代理必须完全初始化为 提供预期的行为,因此您不应在 初始化代码(即@PostConstruct).

使用自定义注释

自定义注释和 AspectJ

此功能仅适用于基于代理的方法,但可以启用 使用 AspectJ 需要付出一些额外的努力。spring-doc.cadn.net.cn

spring-aspects模块仅定义标准注释的一个方面。 如果您已经定义了自己的注释,则还需要为 那些。检查AnnotationCacheAspect举个例子。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 {
}

在前面的示例中,我们定义了自己的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