Spring Batch With Annotation and Caching
Solution 1:
A JobExecutionListener
can be used to populate the cache with reference data before the job is executed and clear the cache after the job is finished.
Here is an example:
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableBatchProcessing
public class MyJob {
private JobBuilderFactory jobs;
private StepBuilderFactory steps;
public MyJob(JobBuilderFactory jobs, StepBuilderFactory steps) {
this.jobs = jobs;
this.steps = steps;
}
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager(); // return the implementation you want
}
@Bean
public Tasklet tasklet() {
return new MyTasklet(cacheManager());
}
@Bean
public Step step() {
return steps.get("step")
.tasklet(tasklet())
.build();
}
@Bean
public JobExecutionListener jobExecutionListener() {
return new CachingJobExecutionListener(cacheManager());
}
@Bean
public Job job() {
return jobs.get("job")
.start(step())
.listener(jobExecutionListener())
.build();
}
class MyTasklet implements Tasklet {
private CacheManager cacheManager;
public MyTasklet(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
String name = (String) cacheManager.getCache("referenceData").get("foo").get();
System.out.println("Hello " + name);
return RepeatStatus.FINISHED;
}
}
class CachingJobExecutionListener implements JobExecutionListener {
private CacheManager cacheManager;
public CachingJobExecutionListener(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public void beforeJob(JobExecution jobExecution) {
// populate cache as needed. Can use a jdbcTemplate to query the db here and populate the cache
cacheManager.getCache("referenceData").put("foo", "bar");
}
@Override
public void afterJob(JobExecution jobExecution) {
// clear cache when the job is finished
cacheManager.getCache("referenceData").clear();
}
}
public static void main(String[] args) throws Exception {
ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean(Job.class);
jobLauncher.run(job, new JobParameters());
}
}
When executed, it prints:
Hello bar
which means data is correctly retrieved from the cache. You would need to adapt the sample to query the database and populate the cache (See comments in code).
Hope this helps.
Solution 2:
You can use ehcache-jsr107 implementation.
Very quick to setup.
Spring and ehcache integration example is available here.
You should be able to setup same with spring batch also.
Hope this hleps