@CacheEvict支持指定key值,进行缓存失效

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

背景

Spring Cache默认的KeyGenerator,在注解中必须指定key(不指定时会以方法中的参数作为key的内容)。如果同个缓存的操作不同的方法, 一个新增另一个失效,那么@CacheEvict和@Cacheable注解上的key必须要保持一致, 这时候如果方法的参数不一致,会导致缓存的操作失败,因为这时候完整的key已经不一致了


默认的SimpleKeyGenerator

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>

application.yml

spring:
  redis:
    host: localhost
    port: 6379

Code

增删查测试类

@Service
public class TestService {
    HashMap<String, Object> data = new HashMap<>();
    {
        data.put("1", "1_x");
        data.put("2", "2_x");
    }

    @CacheEvict(value = "get", key = EMPTY_KEY)
    public void put(String key, Object value) {
        data.put(key, value);
    }

    @CacheEvict(value = "get", key = EMPTY_KEY)
    public void remove(String key) {
        data.remove(key);
    }

    @Cacheable(value = "get", key = EMPTY_KEY)
    public HashMap<String, Object> get() {
        return data;
    }
}

Redis缓存管理配置类

缓存值的写入默认是使用二进制的, 这里改用jackson进行序列化; 有个地方需要注意, EMPTY_KEY需要符合spring-expression表达式的规范, 否则会报错

报错
@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;
    @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()
                .serializeValuesWith(val);
//        defaultCacheConfig.entryTtl(Duration.ofSeconds(120));
        return RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(defaultCacheConfig).build();
    }
    @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);
        };
    }
}

SpringBoot入口类和缓存测试类

@EnableCaching
@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
    @Component
    class CacheRun implements CommandLineRunner {
        @Autowired
        TestService testService;
        @Override
        public void run(String... args) throws Exception {
            HashMap<String, Object> d1 = testService.get();
            testService.remove("1");
            HashMap<String, Object> d2 = testService.get();
            assert !d2.containsKey("1");

            testService.put("3", "3_x");
            HashMap<String, Object> d3 = testService.get();
            assert d3.containsKey("3");
        }
    }
}

结果

Redis
上一篇 下一篇

猜你喜欢

热点阅读