SpringCache自定义注解, 管理Redis缓存过期时间

2021-02-03  本文已影响0人  清蒸三文鱼_

背景

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;
    }
}
上一篇下一篇

猜你喜欢

热点阅读