2018-12-26 · Develop

Spring Boot 集成 Redis

Reids (REmote DIctionary Server)是一个开源(BSD许可)、内存存储的数据结构服务器,可用着数据库来存储 Key-Value 数据,它支持字符串、哈希表、列表、集合、有序集合、位图、地理空间信息等数据类型,同时也可以作为高速缓存和消息队列代理。

Redis 与其他 NOSQL 相比,独特性在于支持复杂的数据结构,这些数据结构通常都与程序的数据机构一致,因此容易理解和使用。

安装 Redis

安装 Redis 我有一篇专门的文章进行讲解 如何在 CentOS 7 上安装 Redis

Spring Boot 集成 Redis

在 Spring Boot 中,引入 spring-boot-starter-data-redis 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

还需要进行配置

spring:
  redis:
    database: 0
    host: 192.168.113.131
    port: 6379
    # password:
    # 连接超时时间
    timeout: 10000

StringRedisTemplate

StringRedisTemplate 是 Spring Boot 默认提供的 Redis 操作接口,适合 Key 和 Value 都是字符串的情况,这种形式对于使用客户端更容易阅读。下面是一些对 Redis 类型所对应的操作方式:

如下的测试代码

@RunWith(SpringRunner.class)
@SpringBootTest
@TestConfiguration
public class RedisTest {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void name() throws Exception {
        stringRedisTemplate.opsForValue().set("TestKey", "TestValue");
    }
}

RedisConnection

Spring Boot 提供了 RedisConnection 抽象,用于低级别 API 操作 Redis, 具体实现有 JRedis 或者 Lettuce 等。

@Test
public void name() throws Exception {
    stringRedisTemplate.execute(new RedisCallback<Object>() {
        @Nullable
        @Override
        public Object doInRedis(RedisConnection connection) throws DataAccessException {
            connection.setNX("TestKey".getBytes(), "TestValue".getBytes());
            return null;
        }
    });
}

Pub/Sub

RedisTemplate 支持 Pub/Sub 功能,发送消息使用如下的示例代码:

stringRedisTemplate.convertAndSend("DefaultChannel", "hello, world");

订阅消息,需要实现 MessageListener 的 onMessage 方法,然后配置监听器进行监听消息通道。

@Configuration
public class RedisConfig {

    class RedisChannelListener implements MessageListener {
        @Override
        public void onMessage(Message message, @Nullable byte[] pattern) {
            byte[] channel = message.getChannel();
            byte[] body = message.getBody();
            // TODO channel 和 body 都是发送时通过 UTF-8 编码转换成的字节。
        }
    }

    @Bean
    MessageListenerAdapter messageListenerAdapter() {
        return new MessageListenerAdapter(new RedisChannelListener());
    }

    @Bean
    RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory, MessageListenerAdapter messageListenerAdapter) {
        RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
        redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
        redisMessageListenerContainer.addMessageListener(messageListenerAdapter, new PatternTopic("DefaultChannel"));
        return redisMessageListenerContainer;
    }
}

序列化策略

由于 StringRedisTemplate 只能处理 key 和 value 都是 String 的数据类型,所以需要使用 RedisTemplate<K, V> ,默认情况下 RedisTemplate<K, V> 使用的是 JDK 的序列策略,即 JdkSerializationRedisSerializer 。使用默认的序列化策略不是很方便,那么我们就可以进行指定序列化策略。

127.0.0.1:6379> keys *
1) "\xac\xed\x00\x05t\x00\aTestKey"
127.0.0.1:6379> get "\xac\xed\x00\x05t\x00\aTestKey"
"\xac\xed\x00\x05t\x00\tTestValue"

如上所示, Key 和 Value 都多了一部分, JDK 序列化对象可以简单理解为第一部分是对象的描述信息,就像“\xac\xed\x00\x05t\x00\a” ,第二部分是对象的数据内容,就是我们需要的 “hollo,world” 部分。所以我们需要自定义序列化策略。

@Autowired
private RedisConnectionFactory redisConnectionFactory;

@Bean
public RedisTemplate<String, Object> redisTemplate() {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setKeySerializer(RedisSerializer.string());
    redisTemplate.setHashKeySerializer(RedisSerializer.string());
    redisTemplate.setHashValueSerializer(RedisSerializer.string());
    redisTemplate.setValueSerializer(RedisSerializer.string());
    redisTemplate.setConnectionFactory(redisConnectionFactory);
    return redisTemplate;
}