Spring 缓存注解 详解

3 篇文章 0 订阅
从 3.1 开始,Spring 引入对 Cache 的支持。其使用方法和原理都类似于 Spring 对事务管理的支持。Spring Cache 是作用在方法上的,其核心思想是 : 当调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存放在缓存中,等到下次利用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回。所以在使用 Spring Cache 时候要保证缓存的方法对于相同的方法参数要有相同的返回结果

使用 Spring Cache 需要做两方面的事 :
1> 声明某些方法使用缓存
2> 配置Spring对Cache的支持

和 Spring 对事务管理的支持一样,Spring对Cache的支持也有基于注解和基于XML配置两种方式


基于注解的支持
Spring 提供注解来支持 Spring Cache。其核心主要是 @Cacheable 和 @CacheEvict。使用 @Cacheable标记的方法在执行后 Spring Cache 将缓存其返回结果,而使用 @CacheEvict标记的方法会在方法执行前或者执行后移除 Spring Cache中的某些元素
1> @Cacheable : 标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring 会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring 在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略
注 : 当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能

@Cacheable 注解 源码如下 :
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Cacheable {
   @AliasFor("cacheNames")
   String[] value() default {};

   @AliasFor("value")
   String[] cacheNames() default {};

   String key() default "";

   String keyGenerator() default "";

   String cacheManager() default "";

   String cacheResolver() default "";

   String condition() default "";

   String unless() default "";

   boolean sync() default false;
}
value、cacheNames 属性 : 指定 Cache名称 表示当前方法的返回值是会被缓存在哪个 Cache上,对应 Cache 名称,名称可以是一个 Cache 也可以是多个 Cache,当需要缓存在多个 Cache 上时其是一个数组

key 属性 : 用来指定 Spring缓存方法的返回结果时对应的 ke。该属性支持 SpringEL表达式,当没有指定该属性时,Spring 将使用默认策略生成 key。先来看看自定义策略,自定义策略是指可以通过 SpringEL 表达式来指定 key。这里的 EL表达式可以使用方法参数及对应的属性,使用方法参数时可以直接使用 "#参数名" 或者 "#p参数index"
@Cacheable(value = "users", key = "#id")
public User find(Integer id) {
    return null;
}
@Cacheable(value = "users", key = "#p0")
public User find(Integer id) {
    return null;
}
@Cacheable(value = "users", key = "#user.id")
public User find(User user) {
    return null;
}
@Cacheable(value = "users", key = "#p0.id")
public User find(User user) {
    return null;
}
@Cacheable(value = "UserCache")
public boolean isReserved(String userId) {
    System.out.println("UserCache:" + userId);
    return false;
}
@Cacheable(value = "UserCache", key = "'user:' + #userId")
public void removeUser(String userId) {
    System.out.println("UserCache remove:" + userId);
}

除上述使用方法参数作为 key之外,Spring 还提供了一个 root对象可以用来生成key,通过该 root对象可以获取到以下信息
属性名称
描述
示例
methodName当前方法名#root.methodName
method当前方法#root.method.name
target当前被调用的对象#root.target
targetClass当前被调用的对象的 class#root.targetClass
args当前方法参数组成的数组#root.args[0]
caches当前被调用的方法使用的 Cache#root.caches[0].name
当要使用 root对象的属性作为 key时,也可以将 "#root" 省略,因为 Spring默认使用的就是 root对象的属性
@Cacheable(value={"users", "xxx"}, key="caches[1].name")
public User find(User user) {
    return null;
}

sync属性 : 在多线程环境下,某些操作可能使用相同参数同步调用。默认情况下,缓存不锁定任何资源,可能导致多次计算,而违反了缓存的目的。对于这些特定的情况,属性 sync 可以指示底层将缓存锁住,使只有一个线程可以进入计算,而其他线程堵塞,直到返回结果更新到缓存中
@Cacheable(cacheNames="foos", sync="true")
public Foo executeExpensiveOperation(String id) {
}

condition属性 : 指定发生的条件,condition属性默认为空,表示将缓存所有的调用情形。其值是通过 SpringEL表达式来指定的,当为true时表示进行缓存处理;当为 false 时表示不进行缓存处理,即每次调用该方法时该方法都会执行一次
@Cacheable(value={"users"}, key="#user.id", condition="#user.id%2==0")
public User find(User user) {
    System.out.println("find user by user " + user);
    return user;
}

还有一个 unless 属性可以用来是决定是否添加到缓存,与 condition不同的是,unless表达式是在方法调用之后进行评估的。如果返回false,才放入缓存 (与condition相反),#result指返回值
@Cacheable(cacheNames="book", condition="#name.length < 32", unless="#result.name.length > 5")
public Book findBook(String name)

2> @CachePut : 在支持 Spring Cache 的环境下,对于使用 @Cacheable标注的方法,Spring 在每次执行前都会检查 Cache 中是否存在相同 key 缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用 @CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。@CachePut 也可以标注在类上和方法上,使用 @CachePut 时可以指定的属性跟 @Cacheable是一样的
@CachePut("users") // 每次都会执行方法,并将结果存入指定的缓存中
public User find(Integer id) {
    return null;
}

3> @CacheEvict : 用来标注在需要清除缓存元素的方法或类上。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict 可以指定的属性有 value、key、condition、allEntries 和 beforeInvocation。其中 value、key 和 condition 的语义与 @Cacheable对应的属性类似。即 value表示清除操作是发生在哪些 Cache 上的 (对应 Cache的名称);key表示需要清除的是哪个 key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。另外 @CacheEvict 还有另外两个属性
allEntries属性 : 是 boolean类型,表示是否需要清除缓存中的所有元素。默认为false,表示不需要。当指定 allEntries为true时,Spring Cache将忽略指定的key 并把缓存信息全部删除
@CacheEvict(value="users", allEntries=true)
public void delete(Integer id) {
    System.out.println("delete user by id: " + id);
}

beforeInvocation属性 : 清除操作默认是在对应方法成功执行之后触发的,即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用 beforeInvocation可以改变触发清除操作的时间,当指定该属性值为 true时,Spring会在调用该方法之前清除缓存中的指定元素
@CacheEvict(value="users", beforeInvocation=true)
public void delete(Integer id) {
    System.out.println("delete user by id: " + id);
}
其实除了使用 @CacheEvict清除缓存元素外,当使用 Ehcache作为实现时,也可以配置 Ehcache自身的驱除策略,其是通过 Ehcache的配置文件来指定的

4> @Caching : @Caching注解可以在一个方法或者类上同时指定多 个Spring Cache 相关的注解。其拥有三个属性 : cacheable、put和evict,分别用于指定@Cacheable、@CachePut 和 @CacheEvict
@Caching(cacheable = @Cacheable("users"),
         evict = { @CacheEvict("cache2"),
                   @CacheEvict(value = "cache3", allEntries = true) })
public User find(Integer id) {
    return null;
}

5> @CacheConfig : 只能用在类上,,允许共享缓存的名称、KeyGenerator、CacheManager 和 CacheResolver,相应的属性可以被方法级别的对应属性值所覆盖

6> 使用自定义注解 :  Spring 允许在配置可缓存的方法时使用自定义的注解,前提是自定义的注解上必须使用对应的注解进行标注
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Cacheable(value="users")
public @interface MyCacheable {
}

@MyCacheable
public User findById(Integer id) {
    System.out.println("find user by id: " + id);
    User user = new User();
    user.setId(id);
    user.setName("Name" + id);
    return user;
}

在 SpringBoot 中只需要添加缓存的类型,可以使 MongoDB、EhCache 或 Redis 等,之后就可以直接使用 Spring 缓存注解 进行缓存


键的生成策略
键用于在缓存唯一标记一个数据,只要键相同那么不管是不是同一个方法都会返回相同的缓存值,键的生成策略有两种,一种是默认策略,一种是自定义策略

默认策略 :  默认的 key生成策略是通过 KeyGenerator生成的,其默认策略如下
1> 如果方法没有参数,则使用 0 作为key
2> 如果只有一个参数的话则使用该参数作为 key
3> 如果参数多余一个的话则使用所有参数的 hashCode 作为 key

如果需要指定自己的默认策略的话,那么可以实现自定义 KeyGenerator,然后指定的 Spring Cache 使用的 KeyGenerator 为自定义的 KeyGenerator
1> 使用基于注解的配置时是通过 cache:annotation-driven指定的
<cache:annotation-driven key-generator="userKeyGenerator"/>
<bean id="userKeyGenerator" class="com.xxx.cache.UserKeyGenerator"/>
2> 使用基于 XML配置时是通过 cache:advice来指定
<cache:advice id="cacheAdvice" cache-manager="cacheManager" key-generator="userKeyGenerator" />
注 : 此时所有的 Cache使用的Key的默认生成策略都是同一个 KeyGenerator

自定义策略 : 可以通过 SpringEL 表达式来指定 key,这里的 EL表达式可以使用方法参数及对应的属性。使用方法参数时,可以直接使用 "#参数名" 或者 "#p参数index"
@Cacheable(value="users", key="#id")
public User find(Integer id) {
    return null;
}
@Cacheable(value="users", key="#p0")
public User find(Integer id) {
    retur nnull;
}
@Cacheable(value="users", key="#user.id")
public User find(User user) {
    return null;
}
@Cacheable(value="users", key="#p0.id")
public User find(User user) {
    return null;
}
@Cacheable(cacheNames="books", key="T(someType).hash(#isbn)")
public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) {
}
@Cacheable(cacheNames="books", key="#map['bookid'].toString()")
public Book findBook(Map<String, Object> map) {
}


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring框架通过Spring Cache提供了一套强大的缓存体系,可以轻松地实现缓存数据,提高应用程序的性能。Spring框架提供了三个主要的注解来实现缓存:@Cacheable、@CachePut和@CacheEvict。 @Cacheable注解用于将方法的结果缓存起来,以便在下次请求时,如果参数相同,则可以直接从缓存中获取结果,而不需要重新计算。该注解适用于如果计算结果比较耗时,或者需要从数据库或其他外部资源中提取数据的情况。 @CachePut注解用于更新缓存中的数据。它与@Cacheable注解类似,但不同的是,它总是更新缓存数据,而不管缓存中是否已经存在该key的值。所以,可以使用这个注解来更新缓存中的数据。 @CacheEvict注解用于从缓存中删除数据。它在需要删除缓存数据的情况下使用。它可以删除指定的key对应的缓存,也可以清空所有缓存数据。 这三个注解都有一个可选参数Named:如果指定了该参数,则缓存将使用指定的名称使用。如果未指定,则使用默认的名称。可以使用不同名称的缓存来存储不同类型的数据,并使用不同的缓存策略来控制它们的存储方式。 除了Spring自带的缓存提供者之外,还可以使用其他的缓存提供者,如Ehcache、Redis、Memcached等等。在使用缓存时,需要注意的是,不同的缓存提供者之间可能会有不同的限制和性能差异。因此,必须根据实际情况选择最适合的缓存提供者和缓存策略,以获取最好的性能和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值