By default, Quartz does not recognize Spring beans configured in applicationContext.xml or with @Bean annotation. If we try to @Autowired these beans in Quartz Job or QuartzJobBean, we will get NullPointerException.
1. Injecting Spring ApplicationContext to QuartzJobBean
The solution is to inject Spring’s ApplicationContext instance to org.quartz.SchedulerContext which is available using org.quartz.JobExecutionContext parameter to executeInternal() method.
1.1. Inject ApplicationContext to SchedulerContext
This is typical SchedulerFactoryBean bean entry. Use setApplicationContextSchedulerContextKey() method. This method set the key of an ApplicationContext reference to expose in the SchedulerContext.
@Bean public SchedulerFactoryBean schedulerFactoryBean() throws IOException, SchedulerException { SchedulerFactoryBean scheduler = new SchedulerFactoryBean(); scheduler.setTriggers(jobOneTrigger(), jobTwoTrigger()); scheduler.setQuartzProperties(quartzProperties()); scheduler.setJobDetails(jobOneDetail(), jobTwoDetail()); scheduler.setApplicationContextSchedulerContextKey("applicationContext"); return scheduler; } 1.2. Access Injected Beans in QuartzJobBean
Now, all you need to do is – get applicationContext reference and start fetching beans as per your need.
import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParametersBuilder; import org.springframework.batch.core.configuration.JobLocator; import org.springframework.batch.core.launch.JobLauncher; import org.springframework.context.ApplicationContext; import org.springframework.scheduling.quartz.QuartzJobBean; public class CustomQuartzJob extends QuartzJobBean { private String jobName; private JobLauncher jobLauncher; private JobLocator jobLocator; public String getJobName() { return jobName; } public void setJobName(String jobName) { this.jobName = jobName; } @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { try { ApplicationContext applicationContext = (ApplicationContext) context.getScheduler().getContext().get("applicationContext"); jobLocator = (JobLocator) applicationContext.getBean(JobLocator.class); jobLauncher = (JobLauncher) applicationContext.getBean(JobLauncher.class); Job job = jobLocator.getJob(jobName); JobParameters params = new JobParametersBuilder() .addString("JobID", String.valueOf(System.currentTimeMillis())) .toJobParameters(); jobLauncher.run(job, params); } catch (Exception e) { e.printStackTrace(); } } } Now when you run quartz job, you will get the jobLocator and jobLauncher instances in executeInternal() method.
2. Conclusion
In this tutorial, we learned to inject the Spring context beans into QuartzJobBean instance so we can get or set the quartz properties in the runtime.
Drop me your questions in the comments section.
Happy Learning !!
Comments