SpringBoot2.0学习笔记:(十) Spring Boot中集成Redis

版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/liujun03/article/details/82891784

一、关于Lettuce

关于在SpringBoot2.0.x版本中集成Redis,我们先看一下官方的迁移文档有什么说的:

Spring Boot2.0迁移指南

当你使用spring-boot-starter-redis的时候,Lettuce现已取代Jedis作为Redis驱动。当你使用更好级别的Spring数据结构时,你会发现变化时清晰的。我们仍然支持Jedis,并且你可以任意切换依赖机制,通过排除io.lettuce:lettuce-core和添加redis.clients.jedis的方式。

Lettuce现已取代Jedis作为Redis驱动

那Lettuce又是个什么呢?与Jedis又有何区别呢?

Lettuce 是一个可伸缩的线程安全的 Redis 客户端,支持同步、异步和响应式模式。多个线程可以共享一个连接实例,而不必担心多线程并发问题。它基于优秀 Netty NIO 框架构建,支持 Redis 的高级功能,如 Sentinel,集群,流水线,自动重新连接和 Redis 数据模型

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

二、SpringBoot集成Redis

对于SpringBoot集成Redis来说,我们需要导入两个包,即:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.4.3</version>
</dependency>

之后再配置文件中配置与redis有关的属性

spring.redis.host=192.168.31.5
spring.redis.port=6379
spring.redis.password=redis
#连接超时时间(毫秒)
spring.redis.timeout=10000ms
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=16
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池最大阻塞等待时间,单位毫秒(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=1000ms
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.shutdown-timeout=100ms

这样关于redis的属性就配置好了,我们可以测试一下:

@Autowired
StringRedisTemplate stringRedisTemplate;
@Autowired
RedisTemplate redisTemplate;

@Test
public void contextLoads() {
    stringRedisTemplate.opsForValue().append("append","asss");
    String append = stringRedisTemplate.opsForValue().get("append");
    System.out.println(append);
}

@Test
public void test01(){
    ValueOperations<String,Object> vo = redisTemplate.opsForValue();
    vo.set("redis","redisTemplate");
    Object name = vo.get("redis");
    System.out.println(name);
}

当然,这一切的前提是你虚拟机中的redis连接成功了,关于在linux中安装启动redis可以参看这篇博客:

Centos 下安装 Redis

这里在配置文件中设置属性时,出现了一个问题:

Value ‘10000’ is not a valid duration

也就是在配置redis连接超时时间时出现的问题,解决方法就是你要在你设置的属性值后面加上单位。

测试完成之后,我们看一下Spring Boot对Redis的自动配置:

按照惯例命名来说,redis的自动配置一般在:RedisAutoConfiguration中。

@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })
public class RedisAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean(name = "redisTemplate")
	public RedisTemplate<Object, Object> redisTemplate(
			RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
		RedisTemplate<Object, Object> template = new RedisTemplate<>();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

	@Bean
	@ConditionalOnMissingBean
	public StringRedisTemplate stringRedisTemplate(
			RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
		StringRedisTemplate template = new StringRedisTemplate();
		template.setConnectionFactory(redisConnectionFactory);
		return template;
	}

}

从注解开始看看:

  • @Configuration:表明这是一个配置类
  • @ConditionalOnClass(RedisOperations.class) :含有这个RedisOperations类才开始redis自动配置,RedisOperations是spring-data-redis jar包中的,在引入pring-boot-starter-data-redis时就引入了。
  • @EnableConfigurationProperties(RedisProperties.class):开启属性的自动注入
  • @Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class }):导入这两个配置文件,这两个配置文件就是根据你导入的jar包来判断是用Lettuce还是Jedis来作为redis驱动的。

之后可以看出在类中使用@Bean注解声明了两个组件注入到容器中去,分别是stringRedisTemplateredisTemplate,在代码中就是用这两个组件来操作缓存的。

这里还要说下,当你使用stringRedisTemplate往redis中写入数据的话,你用redisTemplate是读不到的。因为这两个组件的key与value的序列化方式是不一样的。

进入StringRedisTemplate这个类中可以看一下:

/**
	 * Constructs a new <code>StringRedisTemplate</code> instance. {@link #setConnectionFactory(RedisConnectionFactory)}
	 * and {@link #afterPropertiesSet()} still need to be called.
	 */
public StringRedisTemplate() {
    RedisSerializer<String> stringSerializer = new StringRedisSerializer();
    setKeySerializer(stringSerializer);
    setValueSerializer(stringSerializer);
    setHashKeySerializer(stringSerializer);
    setHashValueSerializer(stringSerializer);
}

可以看到其key与value的序列化是通过StringRedisSerializer实现的。

而RedisTemplate的序列化方式是:

/*
	 * (non-Javadoc)
	 * @see org.springframework.data.redis.core.RedisAccessor#afterPropertiesSet()
	 */
@Override
public void afterPropertiesSet() {

    super.afterPropertiesSet();

    boolean defaultUsed = false;

    if (defaultSerializer == null) {

        defaultSerializer = new JdkSerializationRedisSerializer(
            classLoader != null ? classLoader : this.getClass().getClassLoader());
    }
    
    ......

其默认的序列化方式是JdkSerializationRedisSerializer

三、修改RedisTemplate的序列化方式

这里先推荐一款Redis可视化工具:redis-desktop-manager

安装完成打开连接上redis之后,可以看一下之前存放的数据:

在这里插入图片描述

可以看到,通过RedisTemplate存放的数据经过JdkSerializationRedisSerializer序列化之后,在redis数据库中呈现的样式有点不符合我们的观感,我们可以修改一下其序列化方式:

首先我们导入一下spring-boot-starter-json这个jar包,这是SpringBoot给我们提供的转化json包,其内部引用了jackson-databind这个jar包.

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

之后参照StringRedisTemplate新建一个配置文件

@Configuration
public class RedisTemplateConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        // 设置值(value)的序列化采用FastJsonRedisSerializer。
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        // 设置键(key)的序列化采用StringRedisSerializer。
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

}

在这里,我们给RedisTemplate的key的序列化方式改为StringRedisSerializer,而value的序列化方式改为GenericJackson2JsonRedisSerializer

之后继续测试一下:

@Test
public void test01(){
    ValueOperations<String,Object> vo = redisTemplate.opsForValue();
    //        vo.set("redis","redisTemplate");
    //        Object name = vo.get("redis");
    //        System.out.println(name);
    Student student = new Student(101, "zhangsan", "male");
    vo.set("student:"+student.getId(),student);
    System.out.println(vo.get("student:"+student.getId()));

}

在这里插入图片描述

可以看到,现在使用RedisTemplate存放数据的话,key以String类型存放,value以json类型存放了。

这里在输出的时候System.out.println(vo.get("student:"+student.getId()));遇到一个异常:

cannot deserialize from Object value (no delegate- or property-based Creator

解决办法就是给实体类添加上无参构造器。

以上就是整个的SpringBoot2.0集成Redis的内容了,完整的代码以及测试内容在GitHub上:spring-boot-redis

猜你喜欢

转载自blog.csdn.net/liujun03/article/details/82891784