Redis 是目前业界使用最普遍的内存数据存储。相比 Memcached,Redis 支持更丰富的数据结构,例如 hashes, lists, sets 等,同时支持数据持久化。除此以外,Redis 还提供一些类数据库的特性,好比事务,HA,主从库。能够说 Redis 兼具了缓存系统和数据库的一些特性,所以有着丰富的应用场景。本文介绍 Redis 在 Spring Boot 中两个典型的应用场景。java
<!-- redis 缓存 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- session 缓存 --> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency> <!-- lettuce pool 缓存链接池 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
Spring Boot 提供了对 Redis 集成的组件包:spring-boot-starter-data-redis,spring-boot-starter-data-redis依赖于spring-data-redis 和 lettucegit
Lettuce 是一个可伸缩线程安全的 Redis 客户端,多个线程能够共享同一个 RedisConnection,它利用优秀 netty NIO 框架来高效地管理多个链接。github
spring: redis: host: 127.0.0.1 port: 6379 password: lettuce: pool: # 链接池最大链接数(使用负值表示没有限制) max-active: 8 # 链接池最大阻塞等待时间(使用负值表示没有限制) max-wait: 1000 # 链接池中的最大空闲链接 max-idle: 8 # 链接池中的最小空闲链接 min-idle: 0 # 关闭超时时间 shutdown-timeout: 100
@Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { /** * redisTemplate 序列化使用的jdkSerializeable, 存储二进制字节码, 因此自定义序列化类,方便调试redis * * @param redisConnectionFactory * @return */ @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值 redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); //使用StringRedisSerializer来序列化和反序列化redis的ke redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer()); //开启事务 redisTemplate.setEnableTransactionSupport(true); redisTemplate.setConnectionFactory(redisConnectionFactory); return redisTemplate; } /** * 自定义生成key的策略 * * @return */ @Bean @Override public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... params) { return target.getClass().getSimpleName() + "_" + method.getName() + "_" + StringUtils.arrayToDelimitedString(params, "_"); } }; } }
当不指定缓存的key时,SpringBoot会使用SimpleKeyGenerator生成keyredis
问题:
若是2个方法,参数是同样的,但执行逻辑不一样,那么将会致使执行第二个方法时命中第一个方法的缓存。
解决办法
是在@Cacheable注解参数中指定key,或者本身实现一个KeyGenerator,在注解中指定KeyGenerator。spring
可是若是这样的状况不少,每个都要指定key、KeyGenerator很麻烦。Spring一样提供了方案:继承CachingConfigurerSupport并重写keyGenerator()数据库
@RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class TestRedis1 { @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private RedisTemplate redisTemplate; @Test public void test() throws Exception { stringRedisTemplate.opsForValue().set("aaa", "111"); log.info(String.format("aaa值是:%s", stringRedisTemplate.opsForValue().get("aaa"))); Assert.assertEquals("111", stringRedisTemplate.opsForValue().get("aaa")); } @Test public void testObj() throws Exception { User user = new User("aa@126.com", "aa", "aa123456", "aa", "123"); ValueOperations<String, User> operations = redisTemplate.opsForValue(); operations.set("easy.demo", user); User userRedis = (User) redisTemplate.opsForValue().get("easy.demo"); log.info(String.format("easy.demo值是:%s", userRedis.toString())); } }
分布式系统中,Session 共享有不少的解决方案,其中托管到缓存中应该是最经常使用的方案之一。apache
Spring Session 提供了一套建立和管理 Servlet HttpSession 的方案。Spring Session 提供了集群 Session(Clustered Sessions)功能,默认采用外置的 Redis 来存储 Session 数据,以此来解决 Session 共享的问题。缓存
@Configuration @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400 * 30) public class SessionConfig { }
maxInactiveIntervalInSeconds: 设置 Session 失效时间,使用 Redis Session 以后,原 Spring Boot 的 server.session.timeout 属性再也不生效。安全
@RequestMapping("/uid") public String uid(HttpSession session) { UUID uid = (UUID) session.getAttribute("uid"); if (uid == null) { uid = UUID.randomUUID(); } session.setAttribute("uid", uid); return session.getId(); }
调用以上方法后,打开redis查看,会发现已经把session存入redis了session