1

I am using Spring Boot 2.0.4.RELEASE version with Cache Enabled with default cache provider only No external Cache provider is used.

I have scheduled a batch which run at a specific time everyday. During its run certain method calls which involves Data Access are cached and it works fine.

Now I want to release all the cached items before the next start of function at the scheduled time.

I am not able to implement this feature. Can you all guide me to few ideas or way how to implement it.

This is what I am trying to Implement. I have a JobExecutionListener class marked as @Configuration. I am using its afterJob method to clear all the caches.

@Configuration
@JobScope
public class JobTwoExecutionListener implements JobExecutionListener {

    private static final Logger logger = LoggerFactory.getLogger(JobTwoExecutionListener.class);

    @Autowired
    private CacheManager cacheManager;

    @Override
    public void beforeJob(JobExecution jobExecution) {
        final String methodName = "beforeJob() : ";
        logger.info(methodName + "called");

        if(cacheManager == null) return;

        logger.info(methodName + "CacheManager FOUND. Listing all the caches 
        before Job Run");
        for(String name : cacheManager.getCacheNames()){
            logger.info(methodName + "CACHE_NAME BEFORE JOB " + name);
        }
    }

    @Override
    public void afterJob(JobExecution jobExecution) {
        final String methodName = "afterJob() : ";
        logger.info(methodName + "called");

        performCacheCleanup();
    }

    private void performCacheCleanup(){
        final String methodName = "performCacheCleanup() : ";
        logger.info(methodName + "called");

        if(cacheManager == null){
            logger.info(methodName + "CacheManager NOT FOUND");
            return;
        }

        logger.info(methodName + "CacheManager FOUND. Listing & clearing all the caches after Job Run");

        for(String name : cacheManager.getCacheNames()){
            if(name == null) continue;

            logger.info(methodName + "CLEARING CACHE " + name + " AFTER JOB");
            Cache cache = cacheManager.getCache(name);
            if(cache != null) cache.clear();
        }
    }
}
Nitish Kumar
  • 721
  • 1
  • 10
  • 26
  • have you implemented eh2 cache? – Vikram Saini Sep 28 '18 at 09:42
  • No the default caching only. No external cache provider is used – Nitish Kumar Sep 28 '18 at 09:57
  • I think this is where you'd use a [@CacheEvict](https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/cache/annotation/CacheEvict.html) annotation. Do consider *not* keeping the cache the whole time until the batch is running (unless batch is meant to compute for the cache, and there should otherwise be no cache eviction in there). – M. Prokhorov Sep 28 '18 at 11:15

3 Answers3

5

You can annotate a specific method to call using @CacheEvict

@CacheEvict(value = "cachename", allEntries=true)       
public void doSomethingBeforeEvict(Object object) {
    //do something, cache evicted after this method
}

Or inject a cache manager and remove all the caches

@Service
public class ServiceCacheManagerExample {

    @Autowired 
    private CacheManager cacheManager;     

    public void clearAllCaches(){
        for(String name:cacheManager.getCacheNames()){
            cacheManager.getCache(name).clear();    
        }
    }
}

updated answer based on update question

You are using a wrong @Configuration annotation on your job listener.

ValerioMC
  • 2,926
  • 13
  • 24
  • Spring not injecting CacheManager with @Autowired annotation in a Configuration class – Nitish Kumar Oct 04 '18 at 07:19
  • `@Configuration` you can only define a `@Bean` or pass an object to a `@Bean` it depends how you want to use it, but i don't think it's the right place. If you don't want to use a `@CacheEvict`, you can define a `@Component` or `@Service` to inject it, so you can empty your cache explicitly just when you need. with a service method `emptyCache(s)` for example – ValerioMC Oct 04 '18 at 07:25
  • I don't think that is the case. I have Configuration annotated classes in which I have used Autowired to inject DataSource and EntityManagers. Why CacheManager is not getting injected is something else ! – Nitish Kumar Oct 06 '18 at 07:21
  • Why do you want inject `CacheManager` inside a `@Configuration` class? To evict object? It's the wrong place. If you want to initialize you need to define `CacheManager` as `@Bean` then you can inject in your Service layer – ValerioMC Oct 06 '18 at 08:16
  • There is no need to define CacheManager as @Bean. Spring has already done it. ! I am using JobExecutionListener class to clear all the cache in afterJob() method. I have marked JobExecutionListener as Configuration. In some other services I am able to Autowired CacheManager also ! – Nitish Kumar Oct 06 '18 at 08:22
  • Added code Implementation in the original post. Kindly have a look @valeriomc – Nitish Kumar Oct 06 '18 at 08:29
  • Did not tried this solution. But thanks for the implementation. Tried Mahmoud's solution and it worked. – Nitish Kumar Oct 08 '18 at 06:10
  • I think that probably you should understand ‘@Bean’ ‘@Configuration’ and ‘@Component’ annotation better meaning and usage – ValerioMC Oct 08 '18 at 06:14
1

Populating/Clearing a cache is a typical use case of a JobExecutionListener. In your case, you can create a custom listener and clear the cache in the afterJob method, something like:

@Component
class MyJobExecutionListener extends JobExecutionListenerSupport {

    private CacheManager cacheManager;

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

    @Override
    public void afterJob(JobExecution jobExecution) {
        cacheManager.getCache("mycache").clear();
    }
}

This way, the cache will be clear when your job is executed the next scheduled time.

You can also create a tasklet step that clears the cache and add it as a last step of your job.

There is a similar question to this one, I 'm adding it here for reference: Spring Batch With Annotation and Caching.

Mahmoud Ben Hassine
  • 28,519
  • 3
  • 32
  • 50
  • Worked like a charm ! Thanks. Any difference between JobExecutionListenerSupport Vs JobExecutionListener apart from that one is abstract and other is implementation ? – Nitish Kumar Oct 08 '18 at 06:09
  • Glad it helped. `JobExecutionListenerSupport` is a no op implementation of `JobExecutionListener`. It is a support class that you can use to override only the methods you are interested in and not to have to implement all methods. So you can choose to use one of them, the result is the same. As a side note, looks like you edited the question by adding the listener example after I answered the question. Please mark your edits clearly in the question otherwise my answer will appear somehow stupid since it gives the same solution as in the question.. – Mahmoud Ben Hassine Oct 08 '18 at 08:57
0

before calling your batch again just do a

session.evict(Object)

It will clear all the previous cache associated with that object.

you can also do session.clear() to evict it completely

Vikram Saini
  • 2,713
  • 1
  • 16
  • 33
  • Which session you mentioning here ? And how to get hold of that session ? – Nitish Kumar Sep 28 '18 at 14:06
  • your session with database and you need to autowire it but it needs to be registered in spring container before doing that and i hope you have already done it – Vikram Saini Oct 08 '18 at 05:03