大家好,我是成都12期学员晋良金,今天为大家讲一下如何在SPRINGBOOT中使用SPRING-CACHE+REDIS。
1、背景介绍
从3.1开始,Spring引入了对Cache的支持。其使用方法和原理都类似于Spring对事务管理的支持。Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存放在缓存中,等到下次利用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结果进行返回。
2、知识剖析
Spring-cache的特性有如下几点:
(1)通过少量的配置 annotation 注释即可使得既有代码支持缓存
(2)支持开箱即用 Out-Of-The-Box,即不用安装和部署额外第三方组件即可使用缓存
(3)支持 Spring Express Language,能使用对象的任何属性或者方法来定义缓存的 key 和 condition
(4)支持 AspectJ,并通过其实现任何方法的缓存支持
(5)支持自定义 key 和自定义缓存管理者,具有相当的灵活性和扩展性
在Spring中使用缓存:基于Spring-cache的特性,在代码中使用缓存就变得非常简单了,使用注解或者像配置事务管理一样在xml文件中配置即可,其中注解包括以下五种:
(1)@CacheConfig 类级别的缓存注解,允许共享缓存名称
(2)@Cacheable 触发缓存入口,一般用于查询
(3)@CacheEvict 触发移除缓存,一般用于删除
(4)@CacahePut 更新或插入缓存,更新(插入)数据时使用
(5)@Caching 组合注解,可以一次实现多种缓存操作
它是以方法返回值作为key,并根据SimpleKeyGenerator定义的key生成规则生成key(如果不指定key的话)。
指定Redis作为Spring-cache的缓存,需要配置一下两个东西:
(1)配置Redis连接
(2)配置缓存管理器
3、常见问题
4、解决方案
5、编码实战
配置缓存管理器
@Configuration//相当于beans标签 @EnableCaching//注解驱动的缓存管理器 public class RedisConfiguration extends CachingConfigurerSupport { /* @Autowired private RedisConnectionFactory connectionFactory;*/ /** * @Description: 指定redis主键生成规则:包名+方法名+参数名列表(原有:参数组合) * @return: org.springframework.cache.interceptor.KeyGenerator * @Date: 2018/6/28 17:11 */ /* @Bean @Override public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object o, Method method, Object... objects) { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(o.getClass().getName()); stringBuffer.append("::" + method.getName() + ":"); for (Object object : objects) stringBuffer.append(object.toString()); return stringBuffer.toString(); } }; }*/ /** * @Description: 缓存管理器 * @return: org.springframework.cache.CacheManager * @Date: 2018/6/28 17:12 */ @Bean public CacheManager cacheManager(RedisConnectionFactory connectionFactory) { //通过连接工厂初始化RedisCacheWriter RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory); ClassLoader loader = this.getClass().getClassLoader(); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(om); RedisSerializationContext.SerializationPair<Object> rs = RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer); //设置value序列化方式,如果自带value序列化方式是jdkSerializer,存在redis之中会添加一些东西,人还看不懂 //GenericJackson2JsonRedisSerializer序列化方法存储的大小是jdkSerializer的五分之一,并且是人能够读懂的值 RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(rs); //设置默认过期时间 redisCacheConfiguration.entryTtl(Duration.ofDays(1)); return new RedisCacheManager(redisCacheWriter, redisCacheConfiguration); } /** * @Description: 设置RedisTemplate的序列化方式 * @return: org.springframework.data.redis.core.RedisTemplate<java.lang.String , java.lang.Object> * @Date: 2018/6/28 17:13 */ @Bean(name = "redisTemplate") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); RedisSerializer<String> redisSerializer = new StringRedisSerializer(); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer(om); template.setConnectionFactory(factory); //key序列化方式 template.setKeySerializer(redisSerializer); //value序列化 template.setValueSerializer(genericJackson2JsonRedisSerializer); //value hashmap序列化 template.setHashValueSerializer(genericJackson2JsonRedisSerializer); return template; } }
6、扩展思考
7、参考文献
https://blog.csdn.net/guokezhongdeyuzhou/article/details/79789629
https://blog.csdn.net/u011851478/article/details/70239722
https://www.cnblogs.com/fashflying/p/6908028.html
8、更多讨论
1、Spring-cache除了Redis以外还支持哪些缓存?
通过配置Spring.cache.type时可以看出,还支持:ehcache/jcache/couchbase等,至于Memcached,应该是支持的,虽然Spring.cache.type中没有,但是网上有Spring-cache和Memcached成功整合的例子。
2、使用SimpleKeyGenerator生成的key是由方法参数组合生成的key,如果2个方法,参数是一样的,但执行逻辑不同,那么将会导致执行第二个方法时命中第一个方法的缓存。
(1)通过注解的属性key来指定key的值,而不用SimpleKeyGenerator自动生成的默认值;
(2)继承CachingConfigurerSupport并重写keyGenerator(),改变key的生成规则。
3、@Caching的用法?
它是其他三种用于方法上的注解的组合注解,使用的时候可以指定三个属性(cacheable、put、evict)的值,并且每一个值都是数组。
@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Caching { Cacheable[] cacheable() default {}; CachePut[] put() default {}; CacheEvict[] evict() default {}; }
大概用法如下:
@Caching( put= { @CachePut(key = "\"user\" + #user.id"), @CachePut(key = "#root.methodName")// 可省略#root,Spring默认使用的就是root对象的属性 })