0
votes

I am trying to implement Spring boot cacheable. I want to cache the method response which as ws call.

1) I am able to achieve caching upon request.

 @Cacheable(cacheNames = "mycache", key = "#root.target.cacheKey")
   public String myMethod() {
}

2) I am scheduling cache evict every day at after 1 AM.

@Scheduled(cron = "${1 AM}")
    @CacheEvict(cacheNames = "mycache", key = "#root.target.CACHE_KEY")
    public void clearCache() {

        LOGGER("Cache eviction:: ");

    }

This is also working fine. My question is after evicting without any requests from the browser to @Cacheable annotated method can I call @Cacheable annotated method post evict like to ensure for application safety?

@Scheduled(cron = "${1 AM}")
        @CacheEvict(cacheNames = "mycache", key = "#root.target.CACHE_KEY")
        public void clearCache() {

            LOGGER("Cache eviction:: ");
        myMethod();
        }

This is for application safety .Incase @Cacehable fails to cache response it won't impact the application. I do agree that first request after evict will definitely get inside @Cacheable annotated method and add to cache .But need to make sure that I am following the right approach

Can some one shed some light so that will be useful for me to correct

1
I don't understand why you'd want to do that. Your application will be fine - LppEdd
Yes I understand.. if in case assume there is update made from back end.Cache doesn't have that updated data post evict .In this scenario upon first request only it can be cached which is in realtime. I don't want to take that risk - Pradeep
See my answer. Should be sufficiently detailed - LppEdd

1 Answers

1
votes

So, I was having a look at the sources.

The @CacheEvict AspectJ pointcut is defined as

/**
 * Matches the execution of any public method in a type with the @{@link CacheEvict}
 * annotation, or any subtype of a type with the {@code CacheEvict} annotation.
 */
private pointcut executionOfAnyPublicMethodInAtCacheEvictType() :
    execution(public * ((@CacheEvict *)+).*(..)) && within(@CacheEvict *);

And then grouped in a more generic one

protected pointcut cacheMethodExecution(Object cachedObject) :
    (executionOfAnyPublicMethodInAtCacheableType()
            || executionOfAnyPublicMethodInAtCacheEvictType()
            || ...

The advice which uses this pointcut is an around advice, which means you can inspect the input and output values of the method call, and proceed to the actual call when you want.

Object around(final Object cachedObject) : cacheMethodExecution(cachedObject) {
    MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getSignature();
    Method method = methodSignature.getMethod();

    CacheOperationInvoker aspectJInvoker = new CacheOperationInvoker() {
        public Object invoke() {
            try {
                // Call your method implementation
                return proceed(cachedObject);
            }
            catch (Throwable ex) {
                throw new ThrowableWrapper(ex);
            }
        }
    };

    try {
        // Evict cache, in your case
        return execute(aspectJInvoker, thisJoinPoint.getTarget(), method, thisJoinPoint.getArgs());
    }
    catch (CacheOperationInvoker.ThrowableWrapper th) {
        AnyThrow.throwUnchecked(th.getOriginal());
        return null; // never reached
    }
}

As you can see, the method implementation is called with proceed before executing the cache eviction operation by calling execute.

Therefore your "test" call would have no real meaning.