范培忠 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
四、定义用于测试的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 = "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()的执行效果如下,可见后台日志显示方法仅被实际调用了一次,缓存成功: