SpringBoot整合Redis

使用IntelliJ IDEA创建一个SpringBoot项目后,导入相关依赖

1
2
3
4
5
6
7
<!-- 注:SpringBoot在2.x版本之后将原本使用的Jedis替换成Lettuce,我这里使用的是2.2.5版本 -->
<!-- 使用Jedis:Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线程安全的,这个时候只有使用连接池,为每个Jedis实例增加物理连接 -->
<!-- 使用Lettuce:是基于Netty的,连接实例(StatefulRedisConnection)可以在多个线程间并发访问,应为StatefulRedisConnection是线程安全的,所以一个连接实例(StatefulRedisConnection)就可以满足多线程环境下的并发访问 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  • 可以在SpringBoot的配置文件中找到关于Redis的自动配置类RedisAutoConfiguration:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(RedisOperations.class)
    @EnableConfigurationProperties(RedisProperties.class)
    @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
    public class RedisAutoConfiguration {

    @Bean
    //如果ioc容器中不存在redisTemplate的Bean则使用该默认配置
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
    throws UnknownHostException {
    //由于两个泛型都是Object类型,所以在后期使用时需要进行强制转换
    RedisTemplate<Object, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
    }

    //由于String类型是Redis中最常用的类型,所以单独为String写了一个配置
    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
    throws UnknownHostException {
    StringRedisTemplate template = new StringRedisTemplate();
    template.setConnectionFactory(redisConnectionFactory);
    return template;
    }

    }
  • 通过自动配置类找到Redis对应的配置文件RedisProperties:

在application.properties对Redis进行自定义配置

1
2
spring.redis.host=127.0.0.1
spring.redis.port=6379

编写测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SpringBootTest
class RedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;

@Test
void contextLoads() {
//获取一个连接,并进行刷新操作
//RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
//connection.flushDb();
redisTemplate.opsForValue().set("hello","world");
System.out.println(redisTemplate.opsForValue().get("hello"));
}
}
  • 运行后使用命令查看所有键值,发现我们添加的key-value出现了乱码,是因为还没有设置序列化方式:

  • 查看RedisTemplate类中默认的是使用jdk序列化方式:

  • 下面验证redis中存储的对象必须经过序列化,否则会抛出序列化异常SerializationException。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Component
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    public class User {
    private String name;
    private int age;
    }

    @SpringBootTest
    class RedisApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {
    User user = new User("zhu", 22);
    redisTemplate.opsForValue().set("User",user);
    System.out.println(redisTemplate.opsForValue().get("User"));
    }
    }

    解决方式是将User实现序列化接口:

    1
    2
    3
    4
    5
    6
    7
    8
    @Component
    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    public class User implements Serializable {
    private String name;
    private int age;
    }
  • 下面自定义序列化方式:

    • 通过Redis序列化接口的相关实现类可以看出Spring为我们提供了序列化的不同方式,所以只需要在自定义RedisTemplate中配置好相关序列号方式即可。

    • Redis配置类解决序列化问题:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      @Configuration
      public class RedisConfig {
      @Bean
      public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
      //为了开发方便直接使用RedisTemplate<String, Object>
      RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
      template.setConnectionFactory(factory);

      //Json序列化配置,即使用Jackson2JsonRedisSerializer去解析任意对象
      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);

      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;
      }
      }
    • 配置完毕后重新运行测试代码,查看redis中的键值对发现无乱码: