Spring boot 2.0的Redis缓存应用

范培忠 2018-04-18
Spring Boot2.0.0.RELEASE在2018年3月1日正式发布。2.0下对Redis的使用与之前略有不同。具体实现如下:
一、Maven依赖和配置

添加3个依赖:

org.springframework.boot spring-boot-starter-data-redis org.apache.commons commons-pool2 2.5.0 com.alibaba fastjson 1.2.47

application.yml配置:

spring: redis: #数据库索引 database: 0 host: 127.0.0.1 port: 6379 password: 123 lettuce: pool: #最大连接数 max-active: 8 #最大阻塞等待时间(负数表示没限制) max-wait: -1 #最大空闲 max-idle: 8 #最小空闲 min-idle: 0 #连接超时时间 timeout: 10000

fastjson.properties配置:
本配置是为了解决在1.2.24后因修复漏洞导致的autotype is not support错误。
具体解决办法为声明fastjson.properties文件,将需要打包的类设置白名单等,如下代码所示。

可参考官方通告:https://github.com/alibaba/fastjson/wiki/enable_autotype

fastjson.parser.autoTypeAccept=cn.fanpz.springbootdemoredis3.domain.entity.User

二、自定义序列化器
若要实现对象的缓存,最好定义自己的序列化和反序列化器。使用阿里的fastjson来实现的比较多。
package cn.fanpz.springbootdemoredis3.util; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.serializer.SerializerFeature; import org.springframework.data.redis.serializer.RedisSerializer; import org.springframework.data.redis.serializer.SerializationException; import java.nio.charset.Charset; public class FastJsonRedisSerializer implements RedisSerializer { private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); private Class clazz; public FastJsonRedisSerializer(Class clazz) { super(); this.clazz = clazz; }@Override public byte[] serialize(T t) throws SerializationException { if (null == t) { return new byte[0]; } return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET); }@Override public T deserialize(byte[] bytes) throws SerializationException { if (null == bytes || bytes.length <= 0) { return null; } String str = new String(bytes, DEFAULT_CHARSET); return (T) JSON.parseObject(str, clazz); } }

三、添加RedisConfig配置
在RedisConfig类里定义RedisTemplate的bean和Redis的CacheManager。
package cn.fanpz.springbootdemoredis3.config; import cn.fanpz.springbootdemoredis3.util.FastJsonRedisSerializer; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.cache.CacheManager; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; @EnableCaching @Configuration @ConditionalOnClass(RedisOperations.class) @EnableConfigurationProperties(RedisProperties.class) public class RedisConfig extends CachingConfigurerSupport {@Bean(name = "redisTemplate") @SuppressWarnings("unchecked") @ConditionalOnMissingBean(name = "redisTemplate") public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate template = new RedisTemplate<>(); //使用fastjson序列化 FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class); // value值的序列化采用fastJsonRedisSerializer template.setValueSerializer(fastJsonRedisSerializer); template.setHashValueSerializer(fastJsonRedisSerializer); // key的序列化采用StringRedisSerializer template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setConnectionFactory(redisConnectionFactory); return template; }/*@Bean @ConditionalOnMissingBean(StringRedisTemplate.class) public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; }*///缓存管理器 @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager .RedisCacheManagerBuilder .fromConnectionFactory(redisConnectionFactory); return builder.build(); }}

四、定义用于测试的User类和UserService
User类:
package cn.fanpz.springbootdemoredis3.domain.entity; import java.io.Serializable; public class User implements Serializable {private static final long serialVersionUID = -1L; private String username; private Integer age; public User(String username, Integer age) { this.username = username; this.age = age; }//getter和setter省略}

UserService:
package cn.fanpz.springbootdemoredis3.service.impl; import cn.fanpz.springbootdemoredis3.domain.entity.User; import cn.fanpz.springbootdemoredis3.service.UserService; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @Service public class UserServiceImpl implements UserService { @Override @Cacheable(value = "https://www.it610.com/article/user", key = "'user_'+#username") public User getUser(String username) { System.out.println(username + "进入实现类获取数据!"); return new User("Ttomm", 22); } }

五、编写测试类
package cn.fanpz.springbootdemoredis3; import cn.fanpz.springbootdemoredis3.domain.entity.User; import cn.fanpz.springbootdemoredis3.service.UserService; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.test.context.junit4.SpringRunner; @SuppressWarnings("unchecked") @RunWith(SpringRunner.class) @SpringBootTest public class SpringBootDemoRedis3ApplicationTests { @Autowired private RedisTemplate redisTemplate; @Autowired private UserService userService; @Test //直接使用redisTemplate存取字符串 public void setAndGet() { redisTemplate.opsForValue().set("test:set", "testValue1"); Assert.assertEquals("testValue1", redisTemplate.opsForValue().get("test:set")); }@Test //直接使用redisTemplate存取对象 public void setAndGetAUser() { User user = new User("Tom", 10); redisTemplate.opsForValue().set("test:setUser", user); Assert.assertEquals(user.getUsername(), ((User) redisTemplate.opsForValue().get("test:setUser")).getUsername()); }@Test //使用Redis缓存对象,getUser只会被调用一次 public void testCache() { User user; user = userService.getUser("Ttomm"); user = userService.getUser("Ttomm"); user = userService.getUser("Ttomm"); } }

六、执行效果
testCache()的执行效果如下,可见后台日志显示方法仅被实际调用了一次,缓存成功:

【Spring boot 2.0的Redis缓存应用】Spring boot 2.0的Redis缓存应用
文章图片


    推荐阅读