SpringBoot基于Redis使用SpringCahe

6 篇文章 0 订阅
5 篇文章 0 订阅

Spring Cache 官方文档

注解

@Cacheable

作用于方法或者类上。作用于类上表示该类中所有方法都会走缓存操作

cacheNames/value

缓存名称,可配置多个,调用方法前,会检查是否有命中的缓存,如果有命中至少一个缓存,则返回缓存值,不执行方法操作。更新缓存时,value中所有的缓存名称对应的缓存都会更新。

@Cacheable(value={"a","b"})
public String a(){.....}

@Cacheable(value="b")
public String b(){.....}

// 当调用a方法更新了缓存时,b方法的缓存也会同时更新
keyGenerator

缓存本质上是键值存储,所以缓存方法每次都需要同key进行缓存访问。

默认算法:(实现: org.springframework.cache.interceptor.KeyGenerator )

  • 方法没有参数时,返回SimpleKey.EMPTY
  • 只有一个参数时,返回该参数
  • 有多个参数时,返回所有参数

默认算法只适合参数实现了有效的hashCode()和equals()方法的场景,如果不满足,需要自定义keyGenerator,实现自定义keyGenerator后,在属性中声明要使用的keyGenerator名称即可

key

声明式key,通过SpEL表达式声明key,key属性与 KeyGenerator 属性互斥,设置的时候需要进行二选一

@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)

SpEL还提供了缓存相关的元数据用于key和后续condition,unless的使用

namelacationdescriptionexample
methodNameRoot objectThe name of the method being invoked#root.methodName
methodRoot objectThe method being invoked#root.method.name
targetRoot objectThe target object being invoked#root.target
targetClassRoot objectThe class of the target being invoked#root.targetClass
argsRoot objectThe arguments (as array) used for invoking the target#root.args[0]
cachesRoot objectCollection of caches against which the current method is run#root.caches[0].name
Argument nameEvaluation contextName of any of the method arguments. If the names are not available (perhaps due to having no debug information), the argument names are also available under the #a<#arg> where #argstands for the argument index (starting from 0).#iban or #a0 (you can also use #p0 or #p<#arg>notation as an alias).
resultEvaluation contextThe result of the method call (the value to be cached). Only available in unless expressions, cache put expressions (to compute the key), or cache evict expressions (when beforeInvocation is false). For supported wrappers (such asOptional), #result refers to the actual object, not the wrapper.#result
cacheManage

缓存管理器,用于管理(检索)一个类型缓存,如Redis相关的缓存通过RedisCacheManage来进行管理

cacheResolve

缓存解析器,用于管理缓存管理器,一个CacheResolve拥有一个CacheManage的引用,通过它来进行缓存检索。cacheManage与cacheResolve互斥

sync

是否同步,默认为false,多线程环境下,某些操作以相同的参数并发调用,则对应方法就会被多次执行,达不到缓存的目的,通过该属性,就可以控制只有线程可以通过调用方法获取到结果,其他线程进行等待。

使用该属性时,cacheNames/value只能有一个值,否则会异常,提示only allows a single cache

condition

条件判断,类似于@Conditional注解,condition接收一个结果为boolean类型的表达式,支持SpEL, 当表达式结果为true时才会进行缓存操作

unless

执行后判断,不缓存的条件, 接收一个结果为boolean类型的表达式,支持SpEL,当表达式结果为true时不进行缓存操作

condition 默认为 true,unless 默认为 false

当 condition = false,一定不会缓存;

当 condition = true,且 unless = true,不缓存;

当 condition = true,且 unless = false,缓存;

@CachePut

始终调用该方法并将其结果放入缓存中,主要用于更新缓存

同一个方法上不建议同时使用@Cacheable与@CachePut,@Cacheable会在某些条件下不放入缓存,@CachePut会强制刷新缓存,一起使用可能会出现极端情况

@CacheEvict

删除缓存,需要制定一个或多个收到影响的缓存名称,

allEntries

用于表示是否需要将缓存名称下的所有缓存清楚,不指定表示基于key或keyGeneration条件进行清除,如果配置了allEntries属性,key和 keyGeneration将被忽略

beforeInvocation

表示清除缓存操作在方法执行前还是执行后进行操作,默认为在方法执行之后进行清除操作

@Caching

有时,需要指定多个相同类型的注解(例如@CacheEvict@CachePut)——例如,因为不同缓存之间的条件或键表达式不同。@Caching允许在同一方法上使用多个嵌套的 @Cacheable@CachePut@CacheEvict注释。

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

@CacheConfig

该注解只能作用于类上,允许该类下的操作注解共享缓存名称, keyGenerator,cacheManage,cacheResolve。该注解在类上不会执行任何缓存操作

配置优先级从低到高:

  • 全局配置:cacheManage、keyGenerator
  • 类级别配置 @CacheConfig
  • 操作级别 @Cacheable、@CachePut、@CacheEvict

依赖

 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
-->
<!-- spring-boot-start-web中整合了cache,为方便测试,使用web依赖 -->
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
</dependency>

配置

application.yaml

增加redis配置

spring:
  redis:
    host: xxxxxxx
    password: xxxxxx
    ......

配置类

@EnableCaching
@Configuration
public class RedisCachingConfiguration extends CachingConfigurerSupport {

    /**
     * RedisTemplate配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        this.initDomainRedisTemplate(redisTemplate, redisConnectionFactory);
        return redisTemplate;
    }

    /**
     * 使用Jackson序列化与反序列化value
     */
    private void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setConnectionFactory(factory);
    }

    /**
     * 注册RedisCacheManage
     */
    @Bean("cacheManage")    
    public CacheManager cacheManage(RedisConnectionFactory redisConnectionFactory) {
        //缓存配置对象
        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        redisCacheConfiguration = redisCacheConfiguration
                // 设置超时时间
                .entryTtl(Duration.ofSeconds(10))
		// 设置前缀
                .computePrefixWith(new ProjectCacheKeyPrefix(environment.getProjectName()))
                //如果是空值,不缓存
                .disableCachingNullValues()		
                //设置key序列化器
		.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                //设置value序列化器
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new Jackson2JsonRedisSerializer<>(Object.class)));
        return RedisCacheManager
                .builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
		// 开启与事务同步管理,仅在事务成功时缓存或删除缓存
		.setTransactionAware(true)
		// 默认缓存配置
                .cacheDefaults(redisCacheConfiguration)
		// 不同的缓存名称使用使用指定的缓存配置,可指定多个
		//withCacheConfiguration()
                .build();
    }
	
	// 缓存key前缀生成规则,默认采用缓存名称加::
	class ProjectCacheKeyPrefix implements CacheKeyPrefix {

        private final String projectName;

        ProjectCacheKeyPrefix(String projectName) {
            this.projectName = projectName;
        }

        public String compute(String cacheName) {
            String delimiter = ":";
            return projectName != null ? projectName.concat(delimiter).concat(cacheName).concat(delimiter) : cacheName.concat(delimiter);
        }
    }

    /**
     * 没有指定key时默认,最好使用时指定key值
     */
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            StringBuilder sb = new StringBuilder();
            sb.append(target.getClass().getName());
            sb.append(":").append(method.getName());
            for (Object obj : params) {
                sb.append(":").append(obj.toString());
            }
            return sb.toString();
        };
    }	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值