SpringBoot整合Redis-最佳实践

前言

Spring Boot对很多NoSQL数据库提供了自动化配置的支持,包括为Redis,MongoDB,Neo4j,Elasticsearch,Solr Cassandra、Couchbase和LDAP。本文主要介绍,SpringBoot整合Redis的配置以及本人在SpringBoot项目中使用Redis遇到的问题和解决方法。

Redis

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,Spring Boot为Lettuce和Jedis客户端库提供了基本的自动配置,并提供了由它们提供的抽象Spring Data Redis。本文选取Jedis进行介绍。

引入依赖


    org.springframework.boot
    spring-boot-starter-data-redis


    redis.clients
    jedis

参数配置

spring:
  redis:
    database: 0
    host: localhost
    port: 6379
    password: 123456
    timeout: 2000
    jedis:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0

具体参数配置可以参考:org.springframework.boot.autoconfigure.data.redis.RedisProperties

应用测试

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTest {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    public void testStringRedis() throws Exception {
        stringRedisTemplate.opsForValue().set("aaa", "111");
        Assert.assertEquals("111", stringRedisTemplate.opsForValue().get("aaa"));

    }
}

上面简单的测试演示了如何通过SpringBoot自动配置的StringRedisTemplate对象进行Redis的读写操作,该对象从命名中就可确定支持的是String类型。如果有使用过spring-data-redis一定熟悉RedisTemplate接口,StringRedisTemplate就相当于RedisTemplate的实现。源码如下:

public class StringRedisTemplate extends RedisTemplate {

  /**
   * Constructs a new StringRedisTemplate instance. {@link #setConnectionFactory(RedisConnectionFactory)}
   * and {@link #afterPropertiesSet()} still need to be called.
   */
  public StringRedisTemplate() {
    setKeySerializer(RedisSerializer.string());
    setValueSerializer(RedisSerializer.string());
    setHashKeySerializer(RedisSerializer.string());
    setHashValueSerializer(RedisSerializer.string());
  }

  /**
   * Constructs a new StringRedisTemplate instance ready to be used.
   *
   * @param connectionFactory connection factory for creating new connections
   */
  public StringRedisTemplate(RedisConnectionFactory connectionFactory) {
    this();
    setConnectionFactory(connectionFactory);
    afterPropertiesSet();
  }

  protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
    return new DefaultStringRedisConnection(connection);
  }
}

除了String类型,实战中我们还经常会在Redis中存储对象,这时候我们就会想是否可以使用类似RedisTemplate来初始化并进行操作。

 

实战应用

  • 创建要存储的对象:Person
@Data
public class Person implements Serializable {
    private static final long serialVersionUID = -3958394023121991038L;

    private String username;
    private long age;

    public Person() {
    }

    public Person(String username, long age) {
        this.username = username;
        this.age = age;
    }

}

 

  • 配置针对Person的RedisTemplate实例
@Configuration
public class RedisConfig {

    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        return new JedisConnectionFactory();
    }

    @Bean
    public RedisTemplate personRedisTemplate() {
        RedisTemplate  personRedisTemplate = new RedisTemplate();
        personRedisTemplate.setConnectionFactory(jedisConnectionFactory());
        // 设置key序列化和反序列化类型
        personRedisTemplate.setKeySerializer(new StringRedisSerializer());
        // 设置value序列化和反序列化类型
        personRedisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Person.class));
        return personRedisTemplate;
    }
}

注意:在实例化RedisTemplate可以不用指定其序列化和反序列化的类型,默认是JdkSerializationRedisSerializer

Spring提供了多个序列化类型,按照项目需求灵活选取,如下:

SpringBoot整合Redis-最佳实践_第1张图片

 

  • 创建Person的缓存操作类
@Repository
public class PersonCache {
    @Autowired
    private RedisTemplate personRedisTemplate;

    protected ValueOperations valueOperations;

    @PostConstruct
    public void init() {
        valueOperations = personRedisTemplate.opsForValue();
    }

    public void add(Person person) {
        valueOperations.set(person.getUsername(), person, 10L, TimeUnit.MINUTES);
    }

    public Person load(String key) {
        return valueOperations.get(key);
    }
}
  • 测试
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class ApplicationTest {

    @Autowired
    private PersonCache personCache;

    @Test
    public void testPersonCache() {
        Person person = new Person("张三", 10000);
        personCache.add(person);
        person = new Person("李四", 10001);
        personCache.add(person);

        Assert.assertEquals(10001, personCache.load("李四").getAge());
    }
}

至此SpringBoot整合Redis及简单是用演示结束。但是在实际项目中我们需要缓存的对象往往不只一个,如果我们还想保存缓存其它对象,这里只需要在RedisConfig配置类里实例化对应的RedisTemplate,例如加一个Cilent对象,添加如下代码:

@Bean
public RedisTemplate clientRedisTemplate() {
  RedisTemplate clientRedisTemplate = new RedisTemplate();
  clientRedisTemplate.setConnectionFactory(jedisConnectionFactory());
  clientRedisTemplate.setConnectionFactory(jedisConnectionFactory());
  clientRedisTemplate.setKeySerializer(new StringRedisSerializer());
  clientRedisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Client.class));
  return clientRedisTemplate;
}

 

遇到的坑

  1. SpringBoot默认会装配一个RedisTemplate实例,名称为redisTemplate,自己实例化RedisTemplate避免与SpringBoot默认装配的实例混淆。
  2. 不推荐的使用方式,如下:
// 示例代码一
@Autowired
private RedisTemplate redisTemplate;
protected ValueOperations valueOperations;

@PostConstruct
public void init() {
  valueOperations = redisTemplate.opsForValue();
  redisTemplate.setKeySerializer(new StringRedisSerializer());
  // 使用JDK自带的序列化
  redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
  // 省略操作代码

}
// 示例代码二
@Autowired
private RedisTemplate redisTemplate;
protected ValueOperations valueOperations;

@PostConstruct
public void init() {
  valueOperations = redisTemplate.opsForValue();
  redisTemplate.setKeySerializer(new StringRedisSerializer());
  // 使用JSON序列化
  redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(Map.class));
}

示例代码一和示例代码二中都使用@Autowired注入redisTemplate(SpringBoot自动装配的),这样两个地方使用的是同一个RedisTemplate实例,这样就可能造成反序列化失败

  1. 在设置序列化为Json时,如果报 java: 无法访问com.fasterxml.jackson.databind.JavaType错误,需要添加spring-boot-starter-json依赖:
    

    org.springframework.boot  

    spring-boot-starter-json

我的代码中没有报错是因为spring-boot-starter-web中引用了spring-boot-starter-json

SpringBoot整合Redis-最佳实践_第2张图片

代码示例

github:https://github.com/shallynever/SpringBootStudy/tree/master/SpringBootRedis

 

 

【ZhoujEndless】至此!感觉您的阅读,如有任何问题,欢迎打扰!如有表述错误,劳烦指出!

参考文章:http://blog.didispace.com/springbootredis/

 

 

 

 

 

 

 

 

你可能感兴趣的:(Spring)