Quartz是一个任务调度框架,主要用来操作定时任务。Quartz主要使用的模式是工厂模式和Builder模式
Quartz的核心主要有:
1. Scheduler: 调度器,主要用来调度任务
2. Job:调度任务,任务的业务逻辑都在这里面编写
3. JobDetail: Job的封装器,用于定义Job的数据
4. Trigger:任务触发器,用于设定触发时间
5. JobBuilder:任务构建器,用于创建JobDetail
6. TriggerBuilder:用于创建Trigger
maven依赖:
org.quartz-scheduler
quartz
2.2.2
/**
* job具体逻辑
* Created by Sanisy on 2018/2/16.
*/
public class HelloJob implements Job{
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(format.format(new Date()));
//获取JobDetail定义的参数值
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
System.out.println("userName=" + jobDataMap.getString("userName"));
System.out.println("email=" + jobDataMap.getString("email"));
System.out.println("msg=" + jobDataMap.getString("msg"));
}
}
public class Main {
public static void main(String[] args) throws Exception{
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// define the job and tie it to our HelloJob class
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "group1")
.usingJobData("userName", "Sanisy")
.usingJobData("email", "[email protected]")
.usingJobData("msg", "you should be know nginx、 redis、zookeeper、netty、dubbo、spring cloud、elasticsearch")
.build();
// Trigger the job to run now, and then every 40 seconds
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(2)
.repeatForever())
.build();
// Tell quartz to schedule the job using our trigger
scheduler.scheduleJob(job, trigger);
}
}
Trigger有两种调度设置方式,一种是SimpleScheduleBuilder,另外一种是CronScheduleBuilder。SimpleScheduleBuilder只是简单地设置几分几秒几小时为周期的任务调度;CronScheduleBuilder使用的是linux系统的cron表达式,支持更加复杂的设置,可以定时到哪天哪个时间节点开始,还可以设置循环周期。
public class Main {
public static void main(String[] args) throws Exception{
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// define the job and tie it to our HelloJob class
JobDetail job = JobBuilder.newJob(HelloJob.class)
.withIdentity("myJob", "group1")
.usingJobData("userName", "Sanisy")
.usingJobData("email", "[email protected]")
.usingJobData("msg", "you should be know nginx、 redis、zookeeper、netty、dubbo、spring cloud、elasticsearch")
.build();
// Trigger the job to run now, and then every 40 seconds
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "group1")
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 * * * ?")) //每分钟执行一次
.build();
// Tell quartz to schedule the job using our trigger
scheduler.scheduleJob(job, trigger);
}
}
通过上面的执行日志,我们可以看到Quartz的最终执行Job的execute方法是在JobRunShell中:
public class JobRunShell extends SchedulerListenerSupport implements Runnable {
/**
*
* Create a JobRunShell instance with the given settings.
*
*
* @param scheduler
* The Scheduler
instance that should be made
* available within the JobExecutionContext
.
*/
public JobRunShell(Scheduler scheduler, TriggerFiredBundle bndle) {
this.scheduler = scheduler;
this.firedTriggerBundle = bndle;
}
public void initialize(QuartzScheduler sched)
throws SchedulerException {
this.qs = sched;
Job job = null;
JobDetail jobDetail = firedTriggerBundle.getJobDetail();
job = sched.getJobFactory().newJob(firedTriggerBundle, scheduler);
//创建Job的上下文
this.jec = new JobExecutionContextImpl(scheduler, firedTriggerBundle, job);
}
//这里只显示了核心部分,删除了大部分代码
public void run() {
do {
JobExecutionException jobExEx = null;
Job job = jec.getJobInstance();
job.execute(jec);
}while (true);
}
}
值得注意的是,Quartz默认是采用线程池来执行Job任务的,所以多个任务会被并发执行,也就是说Quartz不会等待上一个时间节点任务执行完毕才去执行下一个时间节点任务。在一些场景下可以通过注解@DisallowConcurrentExecution来避免重复操作某些数据。
更多细节请参考:
官方文档
路边飞~~~的博客
Quartz相对于Spring Schedule的优点是它支持分布式,而 schedule 不支持(需要自己实现,用分布式锁)