摘要
前言
最近在使用WebFlux时发现,SpringBoot提供的@Cacheable,@CachePut,@CacheEvict和@Caching注解不支持响应式方法,SpringBoot官方也没有提供响应式方法的缓存注解,看到网上的一些解决方案都是直接在方法代码中加入缓存数据的代码逻辑,这样虽然可以解决问题,但是代码侵入并不优雅,于是萌生自己写一个基于redis的响应式方法缓存注解的想法,本项目参考SpringBoot提供的@Cacheable,@CachePut,@CacheEvict和@Caching注解声明,但是只是实现了一些基本功能,可以满足绝大部分使用场景的要求,因为SpringBoot早晚会给出官方解决方案,在此之前,不妨一试。
使用示例
- 
本项目已经发布到maven中央仓库,直接在项目中添加依赖即可。 
- 
1.1.0及以下版本是基于springboot:2.4.0构建,可以在springboot2.0+的项目中使用。 
- 
2.x.x及以上版本是基于springboot:2.17.15构建,可以在springboot2.17+(包含3.x+)的项目中使用。 
- 
maven依赖 
| 12
 3
 4
 5
 
 | <dependency><groupId>com.hanqunfeng</groupId>
 <artifactId>reactive-redis-cache-annotation-spring-boot-starter</artifactId>
 <version>{latest-version}</version>
 </dependency>
 
 | 
| 1
 | implementation 'com.hanqunfeng:reactive-redis-cache-annotation-spring-boot-starter:{latest-version}'
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | implementation 'org.springframework.boot:spring-boot-starter-webflux'
 
 
 implementation 'org.springframework.boot:spring-boot-starter-data-redis'
 
 
 implementation 'org.apache.commons:commons-pool2'
 
 
 implementation 'org.springframework.boot:spring-boot-starter-aop'
 
 | 
| 12
 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
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 
 | 
 
 
 
 
 
 
 
 
 
 
 
 
 
 @ReactiveRedisCacheable(cacheName = "sys-user", key = "'find_' + #username")
 public Mono<SysUser> findUserByUsername(String username) {
 return sysUserRepository.findByUsername(username);
 }
 
 @ReactiveRedisCacheable(cacheName = "sys-user", key = "all")
 public Flux<SysUser> findAll() {
 return sysUserRepository.findAll();
 }
 
 
 
 
 
 @ReactiveRedisCacheEvict(cacheName = "sys-user", allEntries = true)
 public Mono<SysUser> add(SysUser sysUser) {
 return sysUserRepository.addSysUser(sysUser.getId(), sysUser.getUsername(), sysUser.getPassword(), sysUser.getEnable()).flatMap(data -> sysUserRepository.findById(sysUser.getId()));
 }
 
 
 
 
 
 
 
 @ReactiveRedisCaching(
 evict = {@ReactiveRedisCacheEvict(cacheName = "sys-user", key = "all")},
 put = {@ReactiveRedisCachePut(cacheName = "sys-user", key = "'find_' + #sysUser.username")}
 )
 public Mono<SysUser> update(SysUser sysUser) {
 Mono<SysUser> save = sysUserRepository.save(sysUser);
 return save;
 }
 
 
 
 
 @ReactiveRedisCacheEvict(cacheName = "sys-user", key="'find_' + #username")
 public Mono<Boolean> deleteByUserName(String username) {
 return sysUserRepository.deleteByUsername(username);
 }
 
 
 | 
RedisTemplate
| 12
 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
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 
 | @Bean@ConditionalOnMissingBean(value = RedisTemplate.class)
 public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
 
 log.debug("ReactiveRedisConfig RedisTemplate");
 ObjectMapper objectMapper = new ObjectMapper();
 objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
 
 objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
 
 
 JavaTimeModule javaTimeModule = new JavaTimeModule();
 
 javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(
 DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
 javaTimeModule.addSerializer(LocalDate.class,
 new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
 javaTimeModule.addSerializer(LocalTime.class,
 new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
 
 javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(
 DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));
 javaTimeModule.addDeserializer(LocalDate.class,
 new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));
 javaTimeModule.addDeserializer(LocalTime.class,
 new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));
 
 
 objectMapper.registerModule(javaTimeModule);
 
 Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
 serializer.setObjectMapper(objectMapper);
 
 RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
 redisTemplate.setConnectionFactory(redisConnectionFactory);
 redisTemplate.setKeySerializer(new StringRedisSerializer());
 redisTemplate.setValueSerializer(serializer);
 redisTemplate.setHashKeySerializer(new StringRedisSerializer());
 redisTemplate.setHashValueSerializer(serializer);
 redisTemplate.afterPropertiesSet();
 
 return redisTemplate;
 }
 
 
 | 
开启debug日志
| 12
 3
 
 | logging:level:
 com.hanqunfeng.reactive.redis.cache: DEBUG
 
 |