Much like before, we have two key concepts:
- job: a job is a runnable class that implements the Job interface
- trigger: a Trigger is a specific schedule for a job. A trigger can only be linked to a job, and a job can be linked to multiple triggers.
Some things to be mindful about:
1. by default Quartz will generate jobs with NO support for DI. To achieve that we need to thank Brian Matthews and jelies:
 public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements  
       ApplicationContextAware {  
   
      private transient AutowireCapableBeanFactory beanFactory;  
   
      @Override  
      public void setApplicationContext(final ApplicationContext context) {  
           beanFactory = context.getAutowireCapableBeanFactory();  
      }  
   
      @Override  
      protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {  
           final Object job = super.createJobInstance(bundle);  
           beanFactory.autowireBean(job);  
           return job;  
      }  
 }  
2. the easiest implementation of Quartz uses an in-memory storage, meaning if the application is restarted or crashes, ALL schedules are lost. You can use a JDBC storage instead for more reliability. You can configure your scheduler in a quartz.properties file, for example minimal settings:
org.quartz.scheduler.instanceName=SOME_NAME
org.quartz.threadPool.threadCount=3
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
We then create a properties bean:
 @Bean  
 public Properties quartzProperties() {  
      PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();  
      propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));  
      Properties properties;  
      try {  
           propertiesFactoryBean.afterPropertiesSet();  
           properties = propertiesFactoryBean.getObject();  
   
      } catch (IOException e) {  
           System.err.println("Cannot load quartz.properties!"); 
      }  
   
      return properties;  
 }  
And the scheduler bean:
 @Bean  
 public SchedulerFactoryBean quartzScheduler() {  
      SchedulerFactoryBean quartzScheduler = new SchedulerFactoryBean();  
        
      AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();  
      jobFactory.setApplicationContext(applicationContext);  
      quartzScheduler.setJobFactory(jobFactory);  
   
      quartzScheduler.setQuartzProperties(quartzProperties());  
   
      return quartzScheduler;  
 }  
3. Quartz uses java Calendar and java Date objects for its operations, you can force a system-wide TimeZone by changing the default (for example to set UTC):
 import java.util.TimeZone;  
   
 TimeZone.setDefault("UTC");  
Then we can start the scheduler:
 quartzScheduler.start();  
4. after a scheduler has been shut down IT CANNOT BE RESTARTED. To shut down the scheduler AND wait for running jobs to complete, use:
 quartzScheduler.shutdown(true);  
Now we can start our coding, for example creating a job:
 //or also .newJob(SomeJob.class)  
 JobDetail job = JobBuilder.newJob(Class.forName("SOME_JOB").asSubclass(Job.class))  
 .withIdentity("SOME_NAME", "SOME_GROUP") //unique identifier for this job  
 .usingJobData(new JobDataMap()) //a HashMap-like structure containing data that every schedule running this job will have  
 .build();  
And our job class might look like this (we inject the scheduler just for testing, it is not necessary):
 public class SampleJob implements Job {  
   
  @Autowired  
  private Scheduler quartzScheduler;  
    
  public void execute(JobExecutionContext context) throws JobExecutionException {  
    
   try {  
    JobDataMap dataMap = context.getMergedJobDataMap();  
      
    System.out.println("Sample job! From scheduler: " + quartzScheduler.getSchedulerName());  
      
    for(Map.Entry<String, Object> data : dataMap.entrySet()) {  
     System.out.println("Got: " + data.getKey() + ": " + data.getValue());  
    }  
      
   } catch (SchedulerException e) {  
    System.err.println("BAD LUCK");  
   }  
  }  
 }  
then we create a simple schedule for it:
 //a trigger that runs forever every second and on a misfire it runs immediately, then continues on normal schedule  
 ScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()  
 .repeatForever() //this trigger will run forever  
 .withMisfireHandlingInstructionFireNow() //you can set whatever misfire handling you need here  
 .withIntervalInSeconds(1); //also you can configure as you need here  
or a more complex schedule:
 //a trigger that runs every day according to "onDaysOfTheWeek", it is a set of integers representing the active days, with Monday = 1  
 //on a misfire it runs immediately, then continues on normal schedule  
 //it starts every day at the specified time (FIRST execution here)  
 //it stops every day at the specified time (LAST execution here). This is NOT a cron expression in format FROM-TO, because in cron, the last execution (TO) would NOT happen  
 //running with a frequency of 1 second  
 ScheduleBuilder scheduleBuilder = DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()  
 .withMisfireHandlingInstructionFireAndProceed()  
 .startingDailyAt(TimeOfDay.hourAndMinuteFromDate(new Date()))  
 .endingDailyAt(TimeOfDay.hourAndMinuteFromDate(new Date()))  
 .withIntervalInSeconds(1)  
 .onDaysOfTheWeek(new HashSet<Integer>());  
We can now create a trigger for that job with our schedule:
 Trigger trigger = newTrigger()  
 .withIdentity("SOME_NAME", "SOME_GROUP") //unique identifier for this trigger  
 .forJob(job)  
 .withSchedule(scheduleBuilder)  
 .usingJobData(new JobDataMap()) //a HashMap-like structure containing data that only this schedule will have  
 .startNow() //or startAt(new Date())  
 .build();  
and finally schedule it:
 quartzScheduler.scheduleJob(job, trigger);  
Lastly, if we want to unschedule ALL jobs (for example in a test environment), we can run:
   
 public void unscheduleJobs() throws SchedulerException {  
   
  for (String group : quartzScheduler.getJobGroupNames()) {  
     
   for (JobKey jobKey : quartzScheduler.getJobKeys(GroupMatcher.jobGroupEquals(group))) {  
     
    final List<Trigger> triggers = (List<Trigger>) quartzScheduler.getTriggersOfJob(jobKey);  
      
    final List<TriggerKey> triggerKeys = new ArrayList<>(triggers.size());  
      
    for(Trigger trigger : triggers) {  
     triggerKeys.add(trigger.getKey());  
    }  
      
    quartzScheduler.unscheduleJobs(triggerKeys);  
    quartzScheduler.deleteJob(jobKey);  
     
   }  
  }  
   
 }  
 
 
No comments:
Post a Comment
With great power comes great responsibility