Quartz是一個(gè)任務(wù)調(diào)度框架缰泡,主要用來操作定時(shí)任務(wù)刀荒。Quartz主要使用的模式是工廠模式和Builder模式
Quartz的核心主要有:
1. Scheduler: 調(diào)度器,主要用來調(diào)度任務(wù)
2. Job:調(diào)度任務(wù),任務(wù)的業(yè)務(wù)邏輯都在這里面編寫
3. JobDetail: Job的封裝器缠借,用于定義Job的數(shù)據(jù)
4. Trigger:任務(wù)觸發(fā)器干毅,用于設(shè)定觸發(fā)時(shí)間
5. JobBuilder:任務(wù)構(gòu)建器,用于創(chuàng)建JobDetail
6. TriggerBuilder:用于創(chuàng)建Trigger
maven依賴:
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.2</version>
</dependency>
/**
* 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定義的參數(shù)值
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", "sanisyme@163.com")
.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有兩種調(diào)度設(shè)置方式柴罐,一種是SimpleScheduleBuilder徽缚,另外一種是CronScheduleBuilder。SimpleScheduleBuilder只是簡(jiǎn)單地設(shè)置幾分幾秒幾小時(shí)為周期的任務(wù)調(diào)度丽蝎;CronScheduleBuilder使用的是linux系統(tǒng)的cron表達(dá)式猎拨,支持更加復(fù)雜的設(shè)置,可以定時(shí)到哪天哪個(gè)時(shí)間節(jié)點(diǎn)開始屠阻,還可以設(shè)置循環(huán)周期红省。
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", "sanisyme@163.com")
.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 * * * ?")) //每分鐘執(zhí)行一次
.build();
// Tell quartz to schedule the job using our trigger
scheduler.scheduleJob(job, trigger);
}
}
通過上面的執(zhí)行日志,我們可以看到Quartz的最終執(zhí)行Job的execute方法是在JobRunShell中:
public class JobRunShell extends SchedulerListenerSupport implements Runnable {
/**
* <p>
* Create a JobRunShell instance with the given settings.
* </p>
*
* @param scheduler
* The <code>Scheduler</code> instance that should be made
* available within the <code>JobExecutionContext</code>.
*/
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);
//創(chuàng)建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默認(rèn)是采用線程池來執(zhí)行Job任務(wù)的,所以多個(gè)任務(wù)會(huì)被并發(fā)執(zhí)行,也就是說Quartz不會(huì)等待上一個(gè)時(shí)間節(jié)點(diǎn)任務(wù)執(zhí)行完畢才去執(zhí)行下一個(gè)時(shí)間節(jié)點(diǎn)任務(wù)呻引。在一些場(chǎng)景下可以通過注解@DisallowConcurrentExecution來避免重復(fù)操作某些數(shù)據(jù)礼仗。
更多細(xì)節(jié)請(qǐng)參考:
官方文檔
路邊飛~~~的博客
Quartz相對(duì)于Spring Schedule的優(yōu)點(diǎn)是它支持分布式,而 schedule 不支持(需要自己實(shí)現(xiàn),用分布式鎖)