6

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)

3
  • what happens if you remove all that and have just a simple @Cacheable on the method? Looks like the annotations are hidden behind a proxy or something. I would use the ORM 2nd level cache support on a SD repository if I were you. Commented Mar 17, 2015 at 16:22
  • Plain caching config works. I've lookad at spring code, it reads cacheResolver correctly but then fails on validation. Looks like a Spring bug to me, but a too obvious one to be truth. Commented Mar 17, 2015 at 20:00
  • I am a bit confused as how you get there. If you have a project that reproduces your problem, please create an issue(jira.spring.io/browse/SPR) and we'll have a look. We'll release 4.1.6 shortly so please do that ASAP. Commented Mar 18, 2015 at 8:35

1 Answer 1

9

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.