spring cache with custom cacheResolver

2019-06-04 06:46发布

问题:

I wand to have dynamic cache names, and spring 4.1 allows that

Since Spring 4.1, the value attribute of the cache annotations are no longer mandatory since this particular information can be provided by the CacheResolver regardless of the content of the annotation.

Notice how I paranoidly set cacheResolver on all possible levels:

@Cacheable(cacheResolver = "defaultCacheResolver")
@CacheConfig(cacheResolver = "defaultCacheResolver")
public interface GatewayRepository extends CrudRepository<Gateway, Integer> {
    @Cacheable(cacheResolver = "defaultCacheResolver")
    Gateway findByBulkId(int bulkId);
}

Spring 4.1.5 still fails to validate the config with error: Caused by: java.lang.IllegalStateException: No cache names could be detected on 'public abstract skunkworks.data.Gateway skunkworks.repos.GatewayRepository.findByBulkId(int)'. Make sure to set the value parameter on the annotation or declare a @CacheConfig at the class-level with the default cache name(s) to use. at org.springframework.cache.annotation.SpringCacheAnnotationParser.validateCacheOperation(SpringCacheAnnotationParser.java:240)

回答1:

I think you should specify cache name somewhere in your code.

In the basic usage, cache name is given in @Cacheable, @CachePut or @CacheEvict annotations.

@Cacheable(cacheNames = "myCache")

You can also specify it in the @CacheConfig which is a class-level annotation.

@CacheConfig(cacheNames = "myCache")

If you need more flexible caching mechanism, you can use CacheResolver. In this case you should create your own CacheResolver. Something along these lines:

public class CustomCacheResolver implements CacheResolver {

    private final CacheManager cacheManager;

    public CustomCacheResolver(CacheManager cacheManager){
        this.cacheManager = cacheManager;
    }

    @Override
    public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {
        Collection<Cache> caches = new ArrayList<>();
        if(context.getTarget().getClass() == GatewayRepository.class){
            if(context.getMethod().getName().equals("findByBulkId")){
                caches.add(cacheManager.getCache("gatewayCache"));
            }
        }

        return caches;
    }
}

In this step, cache name is

gatewayCache

which is defined solely in the cacheresolver and it can be omitted in the annotation side.

After this step, you should register CacheResolver:

@Configuration
@EnableCaching
public class CacheConfiguration extends CachingConfigurerSupport {

    @Bean
    @Override
    public CacheManager cacheManager() {
         // Desired CacheManager
    }

    @Bean
    @Override
    public CacheResolver cacheResolver() {
        return new CustomCacheResolver(cacheManager());
    }
}

And as the last step, you should specify CustomCacheResolver in one of @Cacheable, @CachePut, @CacheConfig etc. annotations.

@Cacheable(cacheResolver="cacheResolver")

You can look here for code samples