@Cacheable注解介绍
关于@Cacheable注解的官方注释,其中关键的一点如图黄色加粗部分
Annotation indicating that the result of invoking a method (or all methods in a class) can be cached.
Each time an advised method is invoked, caching behavior will be applied, checking whether the method has been already invoked for the given arguments. A sensible default simply uses the method parameters to compute the key, but a SpEL expression can be provided via the key attribute, or a custom org.springframework.cache.interceptor.KeyGenerator implementation can replace the default one (see keyGenerator).
If no value is found in the cache for the computed key, the target method will be invoked and the returned value stored in the associated cache. Note that Java8's Optional return types are automatically handled and its content is stored in the cache if present.
This annotation may be used as a meta-annotation to create custom composed annotations with attribute overrides.
如果在缓存中找不到计算键的值,则将调用目标方法,并将返回的值存储在关联的缓存中。请注意,Java8的可选返回类型会自动处理,并且其内容会存储在缓存中 (如果存在)。
代码的样例:
@Cacheable(value = "userCache", key = "#id", unless="#result == null")
public User getById(int id) {
logger.info("获取用户start...");
return userMapper.selectById(id);
}
相较于之前使用缓存,当前基于AOP实现缓存注解实现了代码解耦,将缓存技术实现从业务逻辑代码中抽离出来。
@Cacheable核心源代码实现
@Cacheable注解是Spring框架提供的一个方便的注解,用于在方法调用时缓存结果以便在后续调用中重复使用。它的实现代码是在Spring框架中的CacheInterceptor类中。 CacheInterceptor类是Spring框架中的缓存拦截器,它实现了AOP的切面功能,用于拦截被@Cacheable注解标记的方法,并根据缓存的情况来决定是否执行方法。 在CacheInterceptor类中,@Cacheable注解的实现代码如下:
public class CacheInterceptor extends CacheAspectSupport implements MethodInterceptor, InitializingBean {
// ...
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// ...
// 获取@Cacheable注解
Cacheable cacheable = getCacheableAnnotation(invocation);
if (cacheable != null) {
// 获取缓存key
Object key = generateKey(cacheable.key(), invocation);
// 获取缓存
Cache cache = getCache(cacheable.cacheNames(), invocation);
if (cache != null) {
// 尝试从缓存中获取数据
Cache.ValueWrapper valueWrapper = cache.get(key);
if (valueWrapper != null) {
// 如果缓存中有数据,直接返回
return valueWrapper.get();
}
// 如果缓存中没有数据,执行方法并将结果缓存
Object result = doInvoke(invocation);
if (result != null) {
cache.put(key, result);
}
return result;
}
}
// 如果没有@Cacheable注解,直接执行方法
return doInvoke(invocation);
}
// ...
}
@Cacheable注解参数
除此之外@Cacheable的还携带了如下参数:
value/cacheName
Names of the caches in which method invocation results are stored.
Names may be used to determine the target cache (or caches), matching the qualifier value or bean name of a specific bean definition.
缓存名称可以用来确定目标缓存或缓存,匹配特定bean定义的限定符值或bean名称。
key
Spring Expression Language (SpEL) expression for computing the key dynamically.
Default is "", meaning all method parameters are considered as a key, unless a custom keyGenerator has been configured.
The SpEL expression evaluates against a dedicated context that provides the following meta-data:
#root.method, #root.target, and #root.caches for references to the method, target object, and affected cache(s) respectively.
Shortcuts for the method name (#root.methodName) and target class (#root.targetClass) are also available.
Method arguments can be accessed by index. For instance the second argument can be accessed via #root.args[1], #p1 or #a1. Arguments can also be accessed by name if that information is available.
支持Spring Expression Language(SpEL)表达式,用于动态计算缓存的键(key)。默认情况下,所有方法参数都被视为键,除非已配置自定义的键生成器(keyGenerator)。SpEL表达式会针对一个专用的上下文进行评估,该上下文提供以下元数据:
- #root.method:引用方法
- #root.target:引用目标对象
- #root.caches:引用受影响的缓存
此外,还可以使用以下快捷方式:
- #root.methodName:引用方法名
- #root.targetClass:引用目标类
可以通过索引访问方法参数。例如,第二个参数可以通过#root.args[1]、#p1或#a1来访问。如果有可用的信息,还可以通过名称访问参数。
keyGenerator
The bean name of the custom org.springframework.cache.interceptor.KeyGenerator to use.
Mutually exclusive with the key attribute.
我们可以使用keyGenerator属性来指定Spring框架中自定义的KeyGenerator的bean名称。需要注意的是,这个属性和key属性是互斥的,不能同时使用。
cacheManager
The bean name of the custom org.springframework.cache.CacheManager to use to create a default org.springframework.cache.interceptor.CacheResolver if none is set already.
Mutually exclusive with the cacheResolver attribute.
如果没有设置CacheResolver,可以使用Spring框架中的自定义CacheManager来创建默认的CacheResolver。这可以通过使用cacheManager属性来完成,该属性指定了自定义CacheManager的bean名称。需要注意的是,这个属性和cacheResolver属性是互斥的,不能同时使用。
cacheResolver
The bean name of the custom org.springframework.cache.interceptor.CacheResolver to use.
我们可以通过指定一个自定义的org.springframework.cache.interceptor.CacheResolver的bean名称来使用它。
condition
Spring Expression Language (SpEL) expression used for making the method caching conditional.
Default is "", meaning the method result is always cached.
The SpEL expression evaluates against a dedicated context that provides the following meta-data:
#root.method, #root.target, and #root.caches for references to the method, target object, and affected cache(s) respectively.
Shortcuts for the method name (#root.methodName) and target class (#root.targetClass) are also available.
Method arguments can be accessed by index. For instance the second argument can be accessed via #root.args[1], #p1 or #a1. Arguments can also be accessed by name if that information is available.
支持Spring Expression Language(SpEL)表达式,用于使方法缓存具有条件性。默认情况下,该值为“”,表示方法结果始终被缓存。
SpEL表达式针对一个专用的上下文进行求值,该上下文提供以下元数据:
#root.method,#root.target和#root.caches,分别引用方法、目标对象和受影响的缓存。还可以使用方法名称(#root.methodName)和目标类(#root.targetClass)的快捷方式。
如果有参数信息可以使用,方法参数可以通过索引访问。例如,第二个参数可以通过#root.args[1]、#p1或#a1来访问。
unless
Spring Expression Language (SpEL) expression used to veto method caching.
Unlike condition, this expression is evaluated after the method has been called and can therefore refer to the result.
Default is "", meaning that caching is never vetoed.
The SpEL expression evaluates against a dedicated context that provides the following meta-data:
#result for a reference to the result of the method invocation. For supported wrappers such as Optional, #result refers to the actual object, not the wrapper
#root.method, #root.target, and #root.caches for references to the method, target object, and affected cache(s) respectively.
Shortcuts for the method name (#root.methodName) and target class (#root.targetClass) are also available.
Method arguments can be accessed by index. For instance the second argument can be accessed via #root.args[1], #p1 or #a1. Arguments can also be accessed by name if that information is available.
支持Spring Expression Language(SpEL)表达式,用于否决方法缓存。与Condition条件不同,该表达式在方法调用后进行评估,因此可以引用结果。默认情况下,该值为“”,表示永远不会否决缓存。SpEL表达式针对一个专用的上下文进行求值,该上下文提供以下元数据:#result用于引用方法调用的结果。对于支持的包装器,如Optional,#result引用的是实际对象,而不是包装器。#root.method,#root.target和#root.caches分别引用方法、目标对象和受影响的缓存。还可以使用方法名称(#root.methodName)和目标类(#root.targetClass)的快捷方式。如果有参数信息可以使用,方法参数可以通过索引访问。例如,第二个参数可以通过#root.args[1]、#p1或#a1来访问。
sync
Synchronize the invocation of the underlying method if several threads are attempting to load a value for the same key. The synchronization leads to a couple of limitations:
unless() is not supported
Only one cache may be specified
No other cache-related operation can be combined
This is effectively a hint and the actual cache provider that you are using may not support it in a synchronized fashion. Check your provider documentation for more details on the actual semantics.
如果多个线程尝试为同一个key加载一个值,则可以使用Spring框架来同步调用底层方法。但是,这种同步有一些限制。具体来说,不支持unless()方法,只能指定一个缓存,并且不能组合其他缓存相关操作。需要注意的是,这种同步仅是一个提示,实际使用的缓存提供程序可能不支持同步。因此,建议查看缓存提供程序的文档,以获取有关其实际语义的更多信息。
@CachePut注解介绍
Annotation indicating that a method (or all methods on a class) triggers a cache put operation.
In contrast to the @Cacheable annotation, this annotation does not cause the advised method to be skipped. Rather, it always causes the method to be invoked and its result to be stored in the associated cache. Note that Java8's Optional return types are automatically handled and its content is stored in the cache if present.
This annotation may be used as a meta-annotation to create custom composed annotations with attribute overrides.
注解@CachePut,它可以用于标记一个方法(或类中的所有方法)触发了缓存的put操作。与@Cacheable注解不同的是,该注解不会导致被通知的方法被跳过。相反,它总是会导致方法被调用,并将其结果存储在相关的缓存中。需要注意的是,Java8中的Optional返回类型会自动处理,如果存在,则其内容会被存储在缓存中。
@CachePut注解参数
@CachePut注解和@Cacheable注解参数相同且用法一致。
@CacheEvict注解介绍
Annotation indicating that a method (or all methods on a class) triggers a cache evict operation.
This annotation may be used as a meta-annotation to create custom composed annotations with attribute overrides.
它表示一个方法(或类中的所有方法)会触发一个缓存清除操作。此注解可以用作元注解,以创建带有属性覆盖的自定义组合注解。
@CacheEvict注解参数
@CacheEvict注解和@Cacheable注解参数却少了unless和sync参数,其它参数相同且用法一致,此外还多了两个新的参数allEntries和beforeInvocation。
allEntries
Whether all the entries inside the cache(s) are removed.
By default, only the value under the associated key is removed.
Note that setting this parameter to true and specifying a key is not allowed.
用于指定是否删除缓存中的所有条目。默认情况下,只有与关联键相关的值被删除。需要注意的是,将此参数设置为true并指定一个键是不允许的。
beforeInvocation
Whether the eviction should occur before the method is invoked.
Setting this attribute to true, causes the eviction to occur irrespective of the method outcome (i.e., whether it threw an exception or not).
Defaults to false, meaning that the cache eviction operation will occur after the advised method is invoked successfully (i.e., only if the invocation did not throw an exception).
默认情况下,清除操作发生在方法成功调用后,也就是说,只有在调用没有抛出异常的情况下,缓存清除操作才会发生。然而,将beforeInvocation属性设置为true,将会在方法调用之前发生清除操作,无论方法的执行结果如何。
Tip:首次查看源码如果没有Documented注释,可以手动点击“Download Sources”下载源码(带注释)