In this solution, you will be able to schedule and send ahead of schedule tasks using HTTP requests. In this example, we will create a daily, weekly, and one-year assignment. The application uses Quartz .
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.3</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency>
First we need to create the AutowiringSpringBeanJobFactory extends SpringBeanJobFactory .
- Subclass {@link AdaptableJobFactory}, which also supports Spring-style * dependency injection in bean properties. This is essentially the direct * equivalent of Spring {@link QuartzJobBean} in the form of quartz * {@link org.quartz.spi.JobFactory}. * * *
Applies the scheduler context, job data map, and entries * trigger data map as values โโof bean properties. If the beanfound property is appropriate, the * entry is simply ignored by default. This is similar to QuartzJobBean.
public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { private transient AutowireCapableBeanFactory beanFactory; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { beanFactory = applicationContext.getAutowireCapableBeanFactory(); } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); return job; } }
The second part is the configuration of quartz. In this configuration, we need to create
SchedulerFactoryBean , where we set the global configuration and application context,JobDetailFactoryBean , where we set our job, work group and class,
CronTriggerFactoryBean , where we set the cron expression.
QuartzConfig.class
@Configuration public class QuartzConfig { @Autowired ApplicationContext context; @Bean public SchedulerFactoryBean quartzScheduler(){ SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean(); quartzScheduler.setOverwriteExistingJobs(true); quartzScheduler.setSchedulerName("job-scheduler"); AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory(); jobFactory.setApplicationContext(context); quartzScheduler.setJobFactory(jobFactory); return quartzScheduler; } @Bean @Scope(value = "prototype") public JobDetailFactoryBean getJobBean(String jobName, String jobGroup, Class<?> clazz){ JobDetailFactoryBean bean = new JobDetailFactoryBean(); bean.setJobClass(clazz); bean.setGroup(jobGroup); bean.setName(jobName); return bean; } @Bean @Scope(value = "prototype") public CronTriggerFactoryBean getCronTriggerBean(String cronExpression, String triggerGroup){ CronTriggerFactoryBean bean = new CronTriggerFactoryBean(); bean.setCronExpression(cronExpression); bean.setGroup(triggerGroup); return bean; } }
So, after the setup is complete, we can now create our jobs, where the business logic will be placed. To do this, we need to create a class that implements Job .
@Component public class DailyJob implements Job{ @Override public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("Daily Job runs!"); } }
The DailyJob class DailyJob now ready for planning. We want to plan this work from the outside using an HTTP request. In this example, we have a controller where we can send the job name and cron expression to schedule DailyJob .
@Controller public class JobController { @Autowired private Scheduler scheduler; @Autowired private ApplicationContext context;; @ResponseBody @RequestMapping(value = "/job/create/daily", method = RequestMethod.POST) public ResponseEntity<JobModel> dailyJob(@RequestBody JobModel jobModel) throws SchedulerException { JobDetail jobDetail = context.getBean( JobDetail.class, jobModel.getName(), "MyDailyJob", DailyJob.class); Trigger cronTrigger = context.getBean( Trigger.class, jobModel.getCronExpression(), "MyDailyJob"); scheduler.scheduleJob(jobDetail, cronTrigger); return new ResponseEntity<JobModel>(jobModel, HttpStatus.CREATED); } }
What we see here, we will send a JobModel request with JobModel as @RequestBody . JobModel is a simple Pojo with two attributes, name and cronExpression both lines.
In this method, we must create the bean instances that we preconfigured in our configuration class. First create a JobDetail with Quartz JobDetail.class , the name of your job, the name of the group, and the class to be scheduled (in this case, DailyJob.class ). After that, we need to create a trigger with quartz Trigger.class , cronExpression and the name of the group.
After creating the beans, we need to schedule work now. So, we have an autwired Quartz Scheduler to schedule work. After that, the task is on and ready to do its job.
So let's test the material. Launch the application and send a request for the message /job/create/daily :
{"name":"Job 1", "cronExpression":"0 * * * * ?"}
Here we say that work should be done every minute (just to see that everything is working). In your console you should see every minute Daily Job runs! .
And here are some additional things you can do. For example, get a list of scheduled tasks:
@ResponseBody @RequestMapping("job/list") public List<String> jobList() throws SchedulerException { return scheduler.getJobGroupNames(); }
To delete a task, you can also create endpoints. For instance:
@ResponseBody @RequestMapping(value = "job/delete/daily", method = RequestMethod.POST) public ResponseEntity<Boolean> deleteJob(@RequestBody JobModel jobModel) throws SchedulerException { JobKey jobKey = new JobKey(jobModel.getName(), "MyDailyJob"); return new ResponseEntity<Boolean>(scheduler.deleteJob(jobKey), HttpStatus.OK); }
You can create many different endpoints to get information about current work tasks, how often tasks were completed, transfer tasks, etc. The only important thing is that your name and workgroup (in our case, "MyDailyJob" ) are reusable. This data is required to create a jobKey.
PS: Just show other mappings for other assignments:
@ResponseBody @RequestMapping(value = "/job/create/weekly", method = RequestMethod.POST) public ResponseEntity<JobModel> weeklyJob(@RequestBody JobModel jobModel) throws SchedulerException { JobDetail jobDetail = context.getBean(JobDetail.class, jobModel.getName(), JobGroup.WEEKLY_GROUP.name(), WeeklyJob.class); Trigger cronTrigger = context.getBean(Trigger.class, jobModel.getCronExpression(), JobGroup.WEEKLY_GROUP.name()); scheduler.scheduleJob(jobDetail, cronTrigger); return new ResponseEntity<JobModel>(jobModel, HttpStatus.CREATED); } @ResponseBody @RequestMapping(value = "/job/create/oneTime", method = RequestMethod.POST) public ResponseEntity<JobModel> oneTimeJob(@RequestBody JobModel jobModel) throws SchedulerException { JobDetail jobDetail = context.getBean(JobDetail.class, jobModel.getName(), JobGroup.ONE_TIME_GROUP.name(), OneTimeJob.class); Trigger cronTrigger = context.getBean(Trigger.class, jobModel.getCronExpression(), JobGroup.ONE_TIME_GROUP.name()); scheduler.scheduleJob(jobDetail, cronTrigger); return new ResponseEntity<JobModel>(jobModel, HttpStatus.CREATED); }
The full app is on github