Spring 注解缓存总结

文档:https://docs.spring.io/spring/docs/5.1.9.RELEASE/spring-framework-reference/integration.html#cache
Spring为我们提供了一组缓存的高级接口, 是基于注解的声明式缓存, 非常方便,主要的注解有:
@Cacheable, @CacheEvict, @CachePut, @Caching, @CacheConfig。

@EnableCaching – 全局缓存开关

示例配置

@Configuration
@EnableCaching
public class RedisCacheConfig {
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,
                                     RedisCacheConfiguration redisCacheConfiguration) {
        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(redisCacheConfiguration)
                .build();
    }

    @Bean
    public RedisCacheConfiguration redisCacheConfiguration() {
        RedisSerializationContext.SerializationPair<String> keySerializationPair
                = RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer());
        RedisSerializationContext.SerializationPair<?> valueSerializationPair
                = RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer());
        return RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMillis(expireTime))
                .serializeKeysWith(keySerializationPair)
                .serializeValuesWith(valueSerializationPair)
                .disableCachingNullValues();
    }
}

@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;
}

Cacheable是一个非常重要的注解, 它的主要作用是调用某一个方法时,先根据condition条件确定是否使用缓存,然后根据key去名称为cacheName的缓存块中查找缓存,如果找到直接返回缓存结果,如果没有找到就执行方法体,然后根据unless判断是否将结果放入缓存。
现在来看里面重要的参数:

value and cacheNames

缓存块名称, 缓存块里可放多组key-value, 可以使用@CacheEvict清除整个缓存块的数据。
@Cacheable可以有多个缓存块,每个缓存块都会执行接下来的可能缓存操作。

key

缓存key,是SpEL表达式,默认是"",表示所有方法的参数都参与计算key(实际上是所有参数进行hashcode),如果方法没有参数,那就使用SimpleKey.EMPTY作为key, 和keyGenerator互斥。
表达式中可以使用特定参数:

  • #root.method 当前方法
  • #root.target 当前对象
  • #root.caches 当前缓存
  • #root.methodName 当前方法名
  • #root.targetClass 当前类
  • #root.args[i] 参数(i表示第i个参数,从0开始算)
  • #p0,#p1 … #pi 参数(i表示第i个参数,从0开始算)
  • #a0,#a1 … #ai 参数(i表示第i个参数,从0开始算)

示例

  @Cacheable(cacheNames = "template")
    public Template getById0(Long templateId) {
      //...
    }

    @Cacheable(cacheNames = "template", key = "#root.args[0]")
    public Template getById1(Long templateId) {
      //...
    }

  @Cacheable(cacheNames = "template", key = "#p0")
    public Template getById0(Long templateId) {
      //...
    }

condition

启用缓存条件, 是SpEL表达式, 如果condition不满足, 那@Cacheable就不生效。
condition的测试可以使用和key一样的特定参数。
特别要注意的是condition是在进入方法前测试的。

unless

缓存返回的结果,除非…
意思是满足条件的话,就不缓存了,和condition是相反的意思,其实我觉得叫uncacheCondition更合适。
unless的测试可以使用和key一样的特定参数,然后它还多了一个#result代表返回的结果。
特别要注意的是unless是在方法返回后测试的。
特别要注意的是,如果condition不满足,那么unless就不会再测试了,因为缓存都不起作用了。
例(如果结果返回空就不缓存)

  @Cacheable(cacheNames = "template", key = "#p0", unless="#result==null")
    public Template getById0(Long templateId) {
      //...
    }

keyGenerator

自定义key生成器, 和上面的key互斥, 需要实现以下接口:

@FunctionalInterface
public interface KeyGenerator {
	Object generate(Object target, Method method, Object... params);
}

默认的缓存管理器是容器内的CacheManager bean, 但是我们可以使用cacheManager或者cacheResolver获取特定的缓存块cache.

cacheManager

缓存管理器bean, 和cacheResolver互斥
需要实现以下接口:


public interface CacheManager {
	/**
	 * 返回指定缓存名的缓存块
	 */
	@Nullable
	Cache getCache(String name);
	/**
	 * 返回缓存块名列表
	 */
	Collection<String> getCacheNames();
}

cacheResolver

cache路由,返回相应的缓存块,和cacheManager互斥。

sync

指示在多线程访问key的缓存时是否进行同步, 默认为false, 如果同步会有多种限制,一般不需要(除非 缓存不支持并发读取同一个key)。

注意: 方法返回为Optional的时候, 只有有值的时候才会被缓存, 而#result是指向里面的值,而不是整个Optional.

@CacheEvict – 删除缓存

清除缓存,通常在方法执行后清除

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheEvict {
	@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 "";
	boolean allEntries() default false;
	boolean beforeInvocation() default false;
}

参数含义和@Cache基本一样,不同的是它要清除缓存。
allEntries: 缓存块中的缓存是否要全部移除,默认为false
beforeInvocation:是否在方法执行前删除缓存,默认为false\

@CachePut – 更新缓存

更新/放置缓存, 参数和@Cacheable一样。

@Caching – 多组缓存操作

在一个方法上使用多个缓存注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Caching {
	Cacheable[] cacheable() default {}; // @Cache列表
	CachePut[] put() default {};  //@CachePut列表
	CacheEvict[] evict() default {}; //@CacheEvict列表
}

@CacheConfig – 类级别的缓存设置

以上注解全部是基于方法的, 而@CacheConfig是基于类的缓存配置

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CacheConfig {
	String[] cacheNames() default {};
	String keyGenerator() default "";
	String cacheManager() default "";
	String cacheResolver() default "";
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值