前言
Spring Boot对很多NoSQL数据库提供了自动化配置的支持,包括为Redis,MongoDB,Neo4j,Elasticsearch,Solr Cassandra、Couchbase和LDAP。本文主要介绍,SpringBoot整合Redis的配置以及本人在SpringBoot项目中使用Redis遇到的问题和解决方法。
Redis
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,Spring Boot为Lettuce和Jedis客户端库提供了基本的自动配置,并提供了由它们提供的抽象Spring Data Redis。本文选取Jedis进行介绍。
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
参数配置
spring:
redis:
database: 0
host: localhost
port: 6379
password: 123456
timeout: 2000
jedis:
pool:
max-active: 8
max-idle: 8
min-idle: 0
具体参数配置可以参考:org.springframework.boot.autoconfigure.data.redis.RedisProperties
应用测试
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTest {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void testStringRedis() throws Exception {
stringRedisTemplate.opsForValue().set("aaa", "111");
Assert.assertEquals("111", stringRedisTemplate.opsForValue().get("aaa"));
}
}
上面简单的测试演示了如何通过SpringBoot自动配置的StringRedisTemplate
对象进行Redis的读写操作,该对象从命名中就可确定支持的是String类型。如果有使用过spring-data-redis一定熟悉RedisTemplate<K, V>
接口,StringRedisTemplate
就相当于RedisTemplate<String, String>
的实现。源码如下:
public class StringRedisTemplate extends RedisTemplate<String, String> {
/**
* Constructs a new <code>StringRedisTemplate</code> instance. {@link #setConnectionFactory(RedisConnectionFactory)}
* and {@link #afterPropertiesSet()} still need to be called.
*/
public StringRedisTemplate() {
setKeySerializer(RedisSerializer.string());
setValueSerializer(RedisSerializer.string());
setHashKeySerializer(RedisSerializer.string());
setHashValueSerializer(RedisSerializer.string());
}
/**
* Constructs a new <code>StringRedisTemplate</code> instance ready to be used.
*
* @param connectionFactory connection factory for creating new connections
*/
public StringRedisTemplate(RedisConnectionFactory connectionFactory) {
this();
setConnectionFactory(connectionFactory);
afterPropertiesSet();
}
protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
return new DefaultStringRedisConnection(connection);
}
}
除了String类型,实战中我们还经常会在Redis中存储对象,这时候我们就会想是否可以使用类似RedisTemplate<String, Person>
来初始化并进行操作。
实战应用
- 创建要存储的对象:Person
@Data
public class Person implements Serializable {
private static final long serialVersionUID = -3958394023121991038L;
private String username;
private long age;
public Person() {
}
public Person(String username, long age) {
this.username = username;
this.age = age;
}
}
- 配置针对Person的RedisTemplate实例
@Configuration
public class RedisConfig {
@Bean
JedisConnectionFactory jedisConnectionFactory() {
return new JedisConnectionFactory();
}
@Bean
public RedisTemplate<String, Person> personRedisTemplate() {
RedisTemplate<String, Person> personRedisTemplate = new RedisTemplate();
personRedisTemplate.setConnectionFactory(jedisConnectionFactory());
// 设置key序列化和反序列化类型
personRedisTemplate.setKeySerializer(new StringRedisSerializer());
// 设置value序列化和反序列化类型
personRedisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Person.class));
return personRedisTemplate;
}
}
注意:在实例化RedisTemplate可以不用指定其序列化和反序列化的类型,默认是JdkSerializationRedisSerializer
Spring提供了多个序列化类型,按照项目需求灵活选取,如下:
- 创建Person的缓存操作类
@Repository
public class PersonCache {
@Autowired
private RedisTemplate personRedisTemplate;
protected ValueOperations<String, Person> valueOperations;
@PostConstruct
public void init() {
valueOperations = personRedisTemplate.opsForValue();
}
public void add(Person person) {
valueOperations.set(person.getUsername(), person, 10L, TimeUnit.MINUTES);
}
public Person load(String key) {
return valueOperations.get(key);
}
}
- 测试
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTest {
@Autowired
private PersonCache personCache;
@Test
public void testPersonCache() {
Person person = new Person("张三", 10000);
personCache.add(person);
person = new Person("李四", 10001);
personCache.add(person);
Assert.assertEquals(10001, personCache.load("李四").getAge());
}
}
至此SpringBoot整合Redis及简单是用演示结束。但是在实际项目中我们需要缓存的对象往往不只一个,如果我们还想保存缓存其它对象,这里只需要在RedisConfig配置类里实例化对应的RedisTemplate,例如加一个Cilent对象,添加如下代码:
@Bean
public RedisTemplate<String, Client> clientRedisTemplate() {
RedisTemplate<String, Client> clientRedisTemplate = new RedisTemplate();
clientRedisTemplate.setConnectionFactory(jedisConnectionFactory());
clientRedisTemplate.setConnectionFactory(jedisConnectionFactory());
clientRedisTemplate.setKeySerializer(new StringRedisSerializer());
clientRedisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Client.class));
return clientRedisTemplate;
}
遇到的坑
- SpringBoot默认会装配一个RedisTemplate实例,名称为redisTemplate,自己实例化RedisTemplate避免与SpringBoot默认装配的实例混淆。
- 不推荐的使用方式,如下:
// 示例代码一
@Autowired
private RedisTemplate redisTemplate;
protected ValueOperations<String, App> valueOperations;
@PostConstruct
public void init() {
valueOperations = redisTemplate.opsForValue();
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 使用JDK自带的序列化
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
// 省略操作代码
}
// 示例代码二
@Autowired
private RedisTemplate redisTemplate;
protected ValueOperations<String, Map> valueOperations;
@PostConstruct
public void init() {
valueOperations = redisTemplate.opsForValue();
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 使用JSON序列化
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Map.class));
}
示例代码一和示例代码二中都使用@Autowired注入redisTemplate(SpringBoot自动装配的),这样两个地方使用的是同一个RedisTemplate实例,这样就可能造成反序列化失败
- 在设置序列化为Json时,如果报
java: 无法访问com.fasterxml.jackson.databind.JavaType
错误,需要添加spring-boot-starter-json依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
我的代码中没有报错是因为spring-boot-starter-web中引用了spring-boot-starter-json
代码示例
github:https://github.com/shallynever/SpringBootStudy/tree/master/SpringBootRedis
【ZhoujEndless】至此!感觉您的阅读,如有任何问题,欢迎打扰!如有表述错误,劳烦指出!
参考文章:http://blog.didispace.com/springbootredis/