SpringBoot 集成 Redis


🍖 SpringBoot 集成 Redis(Lettuce)


1. Jedis 和 Lettuce

JedisLettuce 是 Java 操作 Redis 的客户端。在 Spring Boot 1.x 版本默认使用的是 jedis ,而在 Spring Boot 2.x 版本默认使用的就是 Lettuce。关于 Jedis 跟 Lettuce 的区别如下:

  • Jedis在实现上是直接连接的 redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接
  • Lettuce的连接是基于 Netty 的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection 是线程安全的,所以一个连接实例就可以满足多线程环境下的并发访问,当然这个也是可伸缩的设计,一个连接实例不够的情况也可以按需增加连接实例。

2. RedisTemplate 类

SpringBoot 中用来操作 Redis 的类是 RedisTemplate 类:

@Bean
@ConditionalOnMissingBean(name = {"redisTemplate"}) // 我们可以自己定义一个 redisTemplate来替换这个默认的
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
    // 默认的 RedisTemplate 没有过多的设置,redis 对象都是需要序列化!
	// 两个泛型都是 Object, Object 的类型,我们使用需要强制转换 <String, Object>
    RedisTemplate<Object, Object> template = new RedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

@Bean
@ConditionalOnMissingBean // 由于 String 是redis中最常使用的类型,所以单独提出来了一个bean
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
    StringRedisTemplate template = new StringRedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

RedisTemplate 提供了以下方法分别用于对 Redis 的各个数据结构进行操作:

  • opsForValue: 对应 String(字符串)
  • opsForZSet: 对应 ZSet(有序集合)
  • opsForHash: 对应 Hash(哈希)
  • opsForList: 对应 List(列表)
  • opsForSet: 对应 Set(集合)
  • opsForGeo: 对应 GEO(地理位置)

3. 整合测试

① 导入依赖

或者手动导入依赖:

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

SpringBoot2.x 底层访问默认使用 Lettuce

② 配置文件

# 配置redis
spring.redis.host=127.0.0.1
spring.redis.port=6379

③ 测试

@SpringBootTest
class RedisDemoApplicationTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
        redisTemplate.opsForValue().set("mykey","hello");
        System.out.println(redisTemplate.opsForValue().get("mykey"));
    }

}

4. 测试对象的保存

我们编写一个实体类 User,测试一下对象的保存:

@Test
void contextLoads() {
    User user = new User("小牛肉","20");
    redisTemplate.opsForValue().set("user",user);
    System.out.println(redisTemplate.opsForValue().get("user"));
}

🚨 报错:所有的对象都需要序列化。

将实体类序列化:

public class User implements Serializable {

OK!

5. 自定义 RedisTemplate

上示代码中 RedisTemplate<Object,Object> 泛型选用的是两个 Object 类,通常情况下,对于 key 值我们一般会选用 String 类型,使得我们每次都要进行强制类型转换。而且 RedisTemplate 类默认采用的是 jdk 的序列化方式,但在真实的开发中,我们一般使用 Json 来传递对象,接下来我们自定义一个 RedisTemplate<String,Object>(新建一个 configuration.RedisConfig类):

@Configuration
public class RedisConfig {
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        // 为了开发方便,一般直接使用 <String, Object>
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        // 默认是的用jdk序列化的,需要改成 Json 序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // String 的序列化
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}
public class User {

测试:

@Test
void contextLoads() {
    User user = new User("小牛肉","20");
    redisTemplate.opsForValue().set("user",user);
    System.out.println(redisTemplate.opsForValue().get("user"));
}

🎉 Successful !

📚 References


文章作者: Gtwff
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Gtwff !
  目录