Spring Boot 集成 Redis 概览
Spring Boot 提供 spring-boot-starter-data-redis 加载 Redis 相关的依赖,并通过 LettuceConnectionFactory 或者 JedisConnectionFactory 获取与 Redis 的连接。Lettuce 和 Jedis 都是 Java Redis 客户端。Spring Boot 2.x 版本默认使用 Lettuce 连接 Redis Server。Spring Data 提供 RedisTemplate 类作为与 Redis 进行数据交互的核心接口。对于最常用的 String 类型数据,可以使用直接 StringRedisTemplate, 它是 RedisTemplate 针对 String 类型进行扩展的一个子类。Spring Data 还提供 ListOperations,SetOperations,HashOperations 等接口简化对 Redis 对应的各种数据类型的交互。
本文用到的工具
- Java 8
- Spring 5.0.7.RELEASE
- Spring Boot 2.0.3.RELEASE
- Maven 3.5.2
- Intellij IDEA
- Lombok
Maven 依赖
Spring Boot 提供 spring-boot-starter-data-redis 解决 Redis 相关依赖。它为 Lettuce 和 Jedis 提供了基本的自动配置。Spring Boot 2.x 默认使用 Lettuce 作为连接 Redis 的客户端。如果需要配置连接池,需要添加 commons-pool2 的依赖。 pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
Lettuce 相关配置
application.yml
spring:
redis:
database: 0
host: 13.231.xxx.xxx
port: 13808
password: Changeme_123
lecttuce:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
shutdown-timeout: 200ms
max-wait 配置为负数意味着获取连接时一直阻塞直到成功获取连接。
StringRedisTemplate
StringRedisTemplate 是 RedisTemplate 专注于 String 类型的一个子类。它最常用的方式就是通过 StringRedisTemplate 的方法 opsForValue() 获取一个 ValueOperations,然后通过 ValueOperations 接口提供的方法与 Redis Server 进行数据交互。常用的有以下方法,更多方法请查看源码:
setIfAbsent(K key, V value):
Sets key to hold the string value if key is absent.
set(K key, V value): Sets value for key.
get(Object key): Fetches the value of key.
SpringRedisTemplate 的使用:
@RunWith(SpringRunner.class)
@SpringBootApplication(scanBasePackageClasses = RedisConfig.class)
@SpringBootTest
public class RedisDemoApplicationTests {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Test
public void testStringTemplate()
{
stringRedisTemplate.opsForValue().set("Name", "Susan King");
stringRedisTemplate.opsForValue().set("Age", "29");
Assert.assertEquals("Susan King", stringRedisTemplate.opsForValue().get("Name"));
Assert.assertEquals("29", stringRedisTemplate.opsForValue().get("Age"));
}
}
RedisTemplate
除了 Spring 类型的数据之外,我们常常还要使用其他类型的数据,比如各种各样的实体类,这个时候就不能再 StringRedisTemplate 了,需要使用 RedisTemplate。RedisTemplate 类作为与 Redis 进行数据交互的核心接口,提供了丰富的接口,并且能够在对象和二进制数据之间自动进行序列化和反序列化。为了在 Spring Boot 应用中自动注入 RedisTemplte,我们需要在 Config 文件中创建一个
RedisTemplate bean。
RedisConfig.java
@Configuration
@ComponentScan("com.uniquewings.springboot.redisDemo")
public class RedisConfig {
@Autowired
private LettuceConnectionFactory lettuceConnectionFactory;
@Bean
public RedisTemplate redisTemplate ()
{
RedisTemplate template = new RedisTemplate<>();
template.setConnectionFactory(lettuceConnectionFactory);
//如果不设置,将使用默认的 Serializer
// template.setKeySerializer(new StringRedisSerializer());
// template.setValueSerializer(new RedisObjectSerializer());;
return template;
}
}
User.java
@Data
@AllArgsConstructor
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private Integer age;
}
RedisTemplate 的使用
@RunWith(SpringRunner.class)
@SpringBootApplication(scanBasePackageClasses = RedisConfig.class)
@SpringBootTest
public class RedisDemoApplicationTests {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Test
public void testObjectTemplate()
{
redisTemplate.opsForValue().set("BatMan", new User("BatMan", 42));
Assert.assertEquals(Integer.valueOf(42), ((User)redisTemplate.opsForValue().get("BatMan")).getAge());
}
}
自定义 Serializer
public class RedisObjectSerializer implements RedisSerializer<Object>
{
private Converter<Object, byte[]> serializer = new SerializingConverter();
private Converter<byte[], Object> deserializer = new DeserializingConverter();
static final byte[] EMPTY_ARRAY = new byte[0];
@Nullable
@Override
public byte[] serialize(@Nullable Object o) throws SerializationException {
if (null == o)
{
return EMPTY_ARRAY;
}
return serializer.convert(o);
}
@Nullable
@Override
public Object deserialize(@Nullable byte[] bytes) throws SerializationException {
if (isEmpty(bytes))
{
return null;
}
return deserializer.convert(bytes);
}
private boolean isEmpty (byte[] data)
{
return (data == null || data.length == 0);
}
}
在 StringRedisTemplate 和 RedisTemplate 的实例中我们都是通过 opsForValue 返回的接口和数据库交互,实际上 Spring Boot 提供了丰富的接口方便我们对 Redis 对应类型的数据进行操作,下面我们就介绍其中几个。
ListOperations
ListOperations 用来对 Redis 的 List 类型进行操作。常用的方法如下:
leftPush(K key, V value): Prepends value to key.
rightPush(K key, V value): Appends value to key.
leftPop(K key): Removes and returns first element in list stored
at key.
rightPop(K key): Removes and returns last element in list stored at key.
remove(K key, long count, Object value): Removes the first given number (count) of occurences of value from the list stored at key.
index(K key, long index):
Fetches element at index from list at key.
size(K key): Fetches the size of list stored at key.
Now find the example of ListOperations.
SetOperations
SetOperations 用来对 Redis 的 Set 类型进行操作。常用的方法如下:
add(K key, V.. values): Adds values to set at key.
members(K key): Fetches all elements of set at key.
size(Key key): Fetches size of set at key.
remove(K key, Object... values):
Removes given values from set at key and returns the number of removed elements.
HashOperations
HashOperations 用来对 Redis 的 Hash 类型进行操作。常用的方法如下:
putIfAbsent(H key, HK hashKey, HV value): Sets the value of a hash hashKey only if hashKey does not exist.
put(H key, HK hashKey, HV value): Sets the value of a hash
hashKey.
get(H key, Object hashKey): Fetches values for given hashKey from hash at key.
size(H key): Fetches size of hash at key.
entries(H key): Fetches entire hash stored at key.
delete(H key, Object... hashKeys):
Deletes given hash hashKeys at key.
ListOperations 的使用:
@Repository
public class FriendDAO
{
private static final String KEY = "friendKey";
// 把 redisTemplate 转换成 ListOperations 注入
// 转换操作由 ListOperationsEditor 完成.
// 不要使用 @Autowired and @Qualify, 否则不会进行转换
@Resource(name = "redisTemplate")
private ListOperations<String, Person> opsForList;
public void addFriends(Person person)
{
opsForList.leftPush(KEY, person);
}
public long getNumberOfFrends()
{
return opsForList.size(KEY);
}
public Person getFriendAtIndex(Integer index)
{
return opsForList.index(KEY, index);
}
public void removeFriend(Person p)
{
opsForList.remove(KEY, 1, p);
}
public Person popFriend()
{
return opsForList.rightPop(KEY);
}
}
Person.java
@Data
@ToString(includeFieldNames = true)
@EqualsAndHashCode(exclude = "id")
@NoArgsConstructor
@AllArgsConstructor
public class Person implements Serializable
{
private static final long serialVersionUID = 1L;
private int id;
private String name;
private int age;
}
@RunWith(SpringRunner.class)
@SpringBootApplication(scanBasePackageClasses = RedisConfig.class)
@SpringBootTest
public class RedisDemoApplicationTests {
@Autowired
private FriendDAO friendDAO;
@Test
public void testFriend()
{
Person person = new Person(1, "Wings", 29);
friendDAO.addFriends(person);
System.out.println(friendDAO.getFriendAtIndex(0));
Assert.assertEquals(person, friendDAO.getFriendAtIndex(0));
}
}
SetOperations、HashOperations 的使用方式和 ListOperations 类似。
通过以上介绍的方法就可以与 Redis 进行基本的数据交互。更多更高阶的使用请参考官方文档。