SpringBoot 2.x 集成 Redis

windows上搭建redis环境

添加依赖

此处redis客户端使用jedis。

<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <exclusions>
        <exclusion>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </exclusion>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!-- redis 客户端使用jedis -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
  • Jedis
    直接连接 redis server。在多线程环境下是非线程安全的,需要使用连接池,为每个Jedis实例增加物理连接。
  • Lettuce
    连接基于Netty,连接实例可以在多个线程间并发访问。因为连接实例是线程安全的,所以一个连接实例就可以满足多线程环境下的并发访问。

添加配置

2.0 版本之前的一些配置已被移除。使用jedis就配置jedis(如下配置),使用lettuce换下名称即可。

# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接超时时间(毫秒)
spring.redis.timeout=0ms
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1ms
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0

添加redis配置类

  • SpringBoot1.5x之前,Redis配置类如下:
@Configuration
  @EnableCaching
  public class RedisConfig extends CachingConfigurerSupport {

      @Bean
      public KeyGenerator keyGenerator() {
          return new KeyGenerator() {
              @Override
              public Object generate(Object target, Method method, Object... params) {
                  StringBuilder sb = new StringBuilder();
                  sb.append(target.getClass().getName());
                  sb.append(method.getName());
                  for (Object obj : params) {
                      sb.append(obj.toString());
                  }
                  return sb.toString();
              }
          };
      }

      @Bean
      public CacheManager cacheManager(RedisTemplate redisTemplate) {
          RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
          return redisCacheManager;
      }
  }
  • SpringBoot2.0 Redis配置类如下(普遍使用了build模式),
@Configuration
  @EnableCaching
  public class RedisConfig extends CachingConfigurerSupport {
      @Bean
      public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
          RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory).build();
          return redisCacheManager;
      }

      @Bean
      public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
          RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
          redisTemplate.setConnectionFactory(redisConnectionFactory);
          // key序列化
          redisTemplate.setKeySerializer(new StringRedisSerializer());
          // value序列化
          redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Object.class));  
          redisTemplate.afterPropertiesSet();
          return redisTemplate;
      }
  }

缓存管理器

  • RedisCacheManager
  • SimpleCacheManager
  • NoOpCacheManager
  • ConcurrentMapCacheManager
  • CompositeCacheManager
  • EhCacheCacheManager

序列化器

  • GenericToStringSerializer:使用Spring转换服务进行序列化;
  • JacksonJsonRedisSerializer:使用Jackson 1,将对象序列化为JSON;
  • Jackson2JsonRedisSerializer:使用Jackson 2,将对象序列化为JSON;
  • JdkSerializationRedisSerializer:使用Java序列化;
  • OxmSerializer:使用Spring O/X映射的编排器和解排器(marshaler和unmarshaler)实现序列化,用于XML序列化;
  • StringRedisSerializer:序列化String类型的key和value。

redis使用

  • 自动根据方法生成缓存
    访问/api/user/{id}接口,会将结果缓存。代码如下:
@RestController
  @RequestMapping(value = "/api")
  public class StudentController {

      @Autowired
      OmsUserRepository omsUserRepository;

      @GetMapping(value = "/user")
      public List<OmsUser> getAllUser() {
          return this.omsUserRepository.findAll();
      }

      @GetMapping(value = "/user/{id}")
      @Cacheable(value = "user-key")
      public OmsUser getUserById(@PathVariable("id") String id) {
          return omsUserRepository.findById(id).get();
      }
  }
  • @Cacheable表明spring在调用方法之前,首先应该在缓存中查找方法的返回值。如果这个值能够找到,就会返回缓存的值。否则的话,这个方法就会被调用,返回值会放到缓存之中。
  • @CachePut表明spring应该将方法的返回值放到缓存中。在方法的调用前不会检查缓存,方法始终都会被调用。
  • @CacheEvict表明spring应该在缓存中清除一个或多个条目
  • @Caching这是一个分组的注解,能够同时应用多个其它的缓存注解。

自定义key

@Cacheable@CachePut都有一个名为key属性,可使用spel表达式获取值。

  • #root.args:传递给缓存方法的参数,形式为数组
  • #root.caches:该方法执行时所对应的缓存,形式为数组
  • #root.target:目标对象
  • #root.targetClass:目标对象的类,等同#root.target.class
  • #root.method:缓存方法
  • #root.methodName:缓存方法的名字,等同root.method.name
  • #result:方法调用的返回值,不能用在@Cacheable注解上
  • #Argument:任意的方法参数名(如#argName)或参数索引(如#a0#p0)

条件化缓存

@Cacheable@CachePut提供了两个属性用以实现条件化缓存:unlesscondition,这两个属性都接受一个SpEL表达式。

  • unless
  • condition如果表达式计算结果为false,那么在这个方法调用的过程中,缓存是被禁用的。即在这个方法被调用的时候,不会去缓存进行查找,同时返回值也不会放进缓存中。
  • 使用 Template(模版)
    模版种类:
  • StringRedisTemplate
  • RedisTemplate

测试代码:

@RunWith(SpringRunner.class)
  @SpringBootTest
  public class TestRedis {

      @Autowired
      private StringRedisTemplate stringRedisTemplate;

      @Autowired
      private RedisTemplate redisTemplate;

      @Test
      public void test() throws Exception {
          // set
          stringRedisTemplate.opsForValue().set("key", "value");
          // get
          String value = stringRedisTemplate.opsForValue().get("key");
          Assert.assertEquals("value", value);
      }

      @Test
      public void testObj() throws Exception {
          User user = new User("king", "boy", 18);
          ValueOperations<String, User> operations = redisTemplate.opsForValue();
          // set
          operations.set("obj.user.key", user);
          // get
          User user2 = operations.get("obj.user.key");
          Assert.assertEquals(user.getName(), user2.getName());
          Assert.assertEquals(user.getSex(), user2.getSex());
          Assert.assertEquals(user.getAge(), user2.getAge());
      }
  }

测试代码中User user2 = operations.get("obj.user.key")会报错java.util.LinkedHashMap cannot be cast to User。修改redis配置类,如下:

@Configuration
  @EnableCaching
  public class RedisConfig extends CachingConfigurerSupport {

      @Bean
      public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
          RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory).build();
          return redisCacheManager;
      }

      @Bean
      public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
          RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
          redisTemplate.setConnectionFactory(redisConnectionFactory);
          // key序列化
          redisTemplate.setKeySerializer(new StringRedisSerializer());
          // value序列化
          // 使用Jackson ,将对象序列化为JSON
          Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

          //json 转对象类,不设置默认的会将json转成hashmap
          ObjectMapper om = new ObjectMapper();
          om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
          om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
          jackson2JsonRedisSerializer.setObjectMapper(om);

          redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
          redisTemplate.afterPropertiesSet();
          return redisTemplate;
      }
  }
  • 共享 session
  • 添加依赖
<dependency>
      <groupId>org.springframework.session</groupId>
      <artifactId>spring-session-data-redis</artifactId>
  </dependency>
  • session配置
@Configuration
  @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
  public class SessionConfig {
  }
  • 测试
@RequestMapping("/uid")
  String uid(HttpSession session) {
      UUID uid = (UUID) session.getAttribute("uid");
      if (uid == null) {
          uid = UUID.randomUUID();
      }
      session.setAttribute("uid", uid);
      return session.getId();
  }

第一次访问后生成session,第二次及以后访问获取到session值相同。redis存储session形式如下图:

springboot jedis 重试配置 springboot2 jedis_json