背景
RedisCacheManager静态管理缓存不够方便, 加上注解支持自定义的缓存过期时间
Maven
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
Code
配置类
@EnableCaching
@Configuration
@ComponentScan(basePackages = "my.test")
public class RedisCacheConfig extends CachingConfigurerSupport {
public static final String EMPTY_KEY = "'DEFAULT'";
private static final SimpleKeyGenerator SIMPLE_KEY_GENERATOR = new SimpleKeyGenerator();
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Autowired
private ObjectMapper objectMapper;
@Autowired
private ApplicationContext applicationContext;
@Override
@Bean
public CacheManager cacheManager() {
Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
serializer.setObjectMapper(objectMapper);
RedisSerializationContext.SerializationPair val = RedisSerializationContext.SerializationPair.fromSerializer(serializer);
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
//使用冒号做key的连接符, 默认的是::
.computePrefixWith(CacheKeyPrefix.prefixed(":"))
.serializeValuesWith(val);
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(defaultCacheConfig)
.withInitialCacheConfigurations(initRedisCacheConfig(val)).build();
}
public HashMap<String, RedisCacheConfiguration> initRedisCacheConfig(RedisSerializationContext.SerializationPair ser) {
HashMap<String, RedisCacheConfiguration> cacheConfigMap = new HashMap<>();
for (String bean : applicationContext.getBeanNamesForType(Object.class)) {
Class<?> clazz = applicationContext.getType(bean);
if (Objects.isNull(clazz)) {
continue;
}
ReflectionUtils.doWithMethods(clazz, method -> {
ReflectionUtils.makeAccessible(method);
method.getAnnotation(CacheExpire.class);
CacheExpire cacheExpire = AnnotationUtils.findAnnotation(method, CacheExpire.class);
if (Objects.isNull(cacheExpire)) {
return;
}
Cacheable cacheable = AnnotationUtils.findAnnotation(method, Cacheable.class);
if (Objects.nonNull(cacheable)) {
for (String cacheName : cacheable.cacheNames()) {
if (StringUtils.isEmpty(cacheName)) {
continue;
}
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMillis(cacheExpire.type().toMillis(cacheExpire.expire())))
.disableCachingNullValues().serializeValuesWith(ser);
cacheConfigMap.put(cacheName, config);
}
}
});
}
return cacheConfigMap;
}
@Override
@Bean
public KeyGenerator keyGenerator() {
return (o, m, params) -> {
CacheEvict cacheEvict = m.getAnnotation(CacheEvict.class);
if (Objects.nonNull(cacheEvict) && EMPTY_KEY.equals(cacheEvict.key())) {
return EMPTY_KEY;
}
if (params.length == 0) {
return EMPTY_KEY;
}
return SIMPLE_KEY_GENERATOR.generate(o, m, params);
};
}
}
入口类
@EnableCaching
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
@Component
class CacheRun implements CommandLineRunner {
@Autowired
TestService testService;
@Autowired
RedisTemplate<String, String> redisTemplate;
@Override
public void run(String... args) throws Exception {
{
HashMap<String, Object> d1 = testService.get();
Thread.sleep(8000);
String val = redisTemplate.opsForValue().get("get::DEFAULT");
assert val == null;
}
}
}
}
注解类
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CacheExpire {
@AliasFor("expire")
long value() default 60L;
@AliasFor("value")
long expire() default 60L;
TimeUnit type() default TimeUnit.SECONDS;
}
测试类
@Service
public class TestService {
HashMap<String, Object> data = new HashMap<>();
{
data.put("1", "1_x");
data.put("2", "2_x");
}
@Cacheable(value = "get", key = EMPTY_KEY)
@CacheExpire(value = 5)
public HashMap<String, Object> get() {
return data;
}
}
网友评论