阿里的面試官問,若是如今不少調度任務,如何優化,可使用調度池參考:ScheduledExecutor,html
參考:Java 幾種調度任務的Timer、ScheduledExecutor、 開源工具包 Quartz、開源工具包 JCronTabjava
言歸正傳:mysql
Quartz是一個開放源碼項目,專一於任務調度器,提供了極爲普遍的特性如持久化任務,集羣和分佈式任務等。 Quartz核心是調度器,還採用多線程管理。 面試
1.持久化任務:當應用程序中止運行時,全部調度信息不被丟失,當你從新啓動時,調度信息還存在,這就是持久化任務。 spring
2.集羣和分佈式處理:當在集羣環境下,當有配置Quartz的多個客戶端時(節點),採用Quartz的集羣和分佈式處理時,咱們要了解幾點好處sql
1) 一個節點沒法完成的任務,會被集羣中擁有相同的任務的節點取代執行。數據庫
2) Quartz調度是經過觸發器的類別來識別不一樣的任務,在不一樣的節點定義相同的觸發器的類別,這樣在集羣下能穩定的運行,一個節點沒法完成的任務,會被集羣中擁有相同的任務的節點取代執行。tomcat
3)分佈式 體如今 當相同的任務定時在一個時間點,在那個時間點,不會被兩個節點同時執行。 多線程
Quartz的 Task(11 張表)實例化採用數據庫存儲,基於數據庫引擎及 High-Available 的策略(集羣的一種策略)自動協調每一個節點的 Quartz。 oracle
delete from qrtz_fired_triggers; delete from qrtz_simple_triggers; delete from qrtz_simprop_triggers; delete from qrtz_cron_triggers; delete from qrtz_blob_triggers; delete from qrtz_triggers; delete from qrtz_job_details; delete from qrtz_calendars; delete from qrtz_paused_trigger_grps; delete from qrtz_locks; delete from qrtz_scheduler_state; CREATE TABLE qrtz_job_details ( SCHED_NAME VARCHAR2(120) NOT NULL, JOB_NAME VARCHAR2(200) NOT NULL, JOB_GROUP VARCHAR2(200) NOT NULL, DESCRIPTION VARCHAR2(250) NULL, JOB_CLASS_NAME VARCHAR2(250) NOT NULL, IS_DURABLE VARCHAR2(1) NOT NULL, IS_NONCONCURRENT VARCHAR2(1) NOT NULL, IS_UPDATE_DATA VARCHAR2(1) NOT NULL, REQUESTS_RECOVERY VARCHAR2(1) NOT NULL, JOB_DATA BLOB NULL, CONSTRAINT QRTZ_JOB_DETAILS_PK PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) ); CREATE TABLE qrtz_triggers ( SCHED_NAME VARCHAR2(120) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, JOB_NAME VARCHAR2(200) NOT NULL, JOB_GROUP VARCHAR2(200) NOT NULL, DESCRIPTION VARCHAR2(250) NULL, NEXT_FIRE_TIME NUMBER(13) NULL, PREV_FIRE_TIME NUMBER(13) NULL, PRIORITY NUMBER(13) NULL, TRIGGER_STATE VARCHAR2(16) NOT NULL, TRIGGER_TYPE VARCHAR2(8) NOT NULL, START_TIME NUMBER(13) NOT NULL, END_TIME NUMBER(13) NULL, CALENDAR_NAME VARCHAR2(200) NULL, MISFIRE_INSTR NUMBER(2) NULL, JOB_DATA BLOB NULL, CONSTRAINT QRTZ_TRIGGERS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), CONSTRAINT QRTZ_TRIGGER_TO_JOBS_FK FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP) ); CREATE TABLE qrtz_simple_triggers ( SCHED_NAME VARCHAR2(120) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, REPEAT_COUNT NUMBER(7) NOT NULL, REPEAT_INTERVAL NUMBER(12) NOT NULL, TIMES_TRIGGERED NUMBER(10) NOT NULL, CONSTRAINT QRTZ_SIMPLE_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), CONSTRAINT QRTZ_SIMPLE_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE qrtz_cron_triggers ( SCHED_NAME VARCHAR2(120) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, CRON_EXPRESSION VARCHAR2(120) NOT NULL, TIME_ZONE_ID VARCHAR2(80), CONSTRAINT QRTZ_CRON_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), CONSTRAINT QRTZ_CRON_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE qrtz_simprop_triggers ( SCHED_NAME VARCHAR2(120) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, STR_PROP_1 VARCHAR2(512) NULL, STR_PROP_2 VARCHAR2(512) NULL, STR_PROP_3 VARCHAR2(512) NULL, INT_PROP_1 NUMBER(10) NULL, INT_PROP_2 NUMBER(10) NULL, LONG_PROP_1 NUMBER(13) NULL, LONG_PROP_2 NUMBER(13) NULL, DEC_PROP_1 NUMERIC(13,4) NULL, DEC_PROP_2 NUMERIC(13,4) NULL, BOOL_PROP_1 VARCHAR2(1) NULL, BOOL_PROP_2 VARCHAR2(1) NULL, CONSTRAINT QRTZ_SIMPROP_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), CONSTRAINT QRTZ_SIMPROP_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE qrtz_blob_triggers ( SCHED_NAME VARCHAR2(120) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, BLOB_DATA BLOB NULL, CONSTRAINT QRTZ_BLOB_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), CONSTRAINT QRTZ_BLOB_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) ); CREATE TABLE qrtz_calendars ( SCHED_NAME VARCHAR2(120) NOT NULL, CALENDAR_NAME VARCHAR2(200) NOT NULL, CALENDAR BLOB NOT NULL, CONSTRAINT QRTZ_CALENDARS_PK PRIMARY KEY (SCHED_NAME,CALENDAR_NAME) ); CREATE TABLE qrtz_paused_trigger_grps ( SCHED_NAME VARCHAR2(120) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, CONSTRAINT QRTZ_PAUSED_TRIG_GRPS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP) ); CREATE TABLE qrtz_fired_triggers ( SCHED_NAME VARCHAR2(120) NOT NULL, ENTRY_ID VARCHAR2(95) NOT NULL, TRIGGER_NAME VARCHAR2(200) NOT NULL, TRIGGER_GROUP VARCHAR2(200) NOT NULL, INSTANCE_NAME VARCHAR2(200) NOT NULL, FIRED_TIME NUMBER(13) NOT NULL, SCHED_TIME NUMBER(13) NOT NULL, PRIORITY NUMBER(13) NOT NULL, STATE VARCHAR2(16) NOT NULL, JOB_NAME VARCHAR2(200) NULL, JOB_GROUP VARCHAR2(200) NULL, IS_NONCONCURRENT VARCHAR2(1) NULL, REQUESTS_RECOVERY VARCHAR2(1) NULL, CONSTRAINT QRTZ_FIRED_TRIGGER_PK PRIMARY KEY (SCHED_NAME,ENTRY_ID) ); CREATE TABLE qrtz_scheduler_state ( SCHED_NAME VARCHAR2(120) NOT NULL, INSTANCE_NAME VARCHAR2(200) NOT NULL, LAST_CHECKIN_TIME NUMBER(13) NOT NULL, CHECKIN_INTERVAL NUMBER(13) NOT NULL, CONSTRAINT QRTZ_SCHEDULER_STATE_PK PRIMARY KEY (SCHED_NAME,INSTANCE_NAME) ); CREATE TABLE qrtz_locks ( SCHED_NAME VARCHAR2(120) NOT NULL, LOCK_NAME VARCHAR2(40) NOT NULL, CONSTRAINT QRTZ_LOCKS_PK PRIMARY KEY (SCHED_NAME,LOCK_NAME) ); create index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY); create index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP); create index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP); create index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP); create index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME); create index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP); create index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE); create index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE); create index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE); create index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME); create index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME); create index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME); create index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE); create index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME); create index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY); create index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP); create index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP); create index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP); create index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP);
我在新建一個張表,爲了方便頁面能對每一個任務進行管理,能對具體某個任務設置開始時間、結束時間、執行的方法、刪除等, 以下面圖所示:
在這邊能夠管理開始時間和結束時間和cronExpression值,方便管理對應表的設計:
表都設計好了,整理Quartz集成springMVC的具體的實現。
對spring的@component 的說明:@component (把普通pojo實例化到spring容器中,至關於配置文件中的<bean id="" class=""/>)
1.舉例兩個任務具體實現功能,列如quartzJobA和quartzJobB任務要作什麼,新建了兩個類和方法。
#Main Scheduler Settings org.quartz.scheduler.instanceName=quartzScheduler org.quartz.scheduler.instanceId=AUTO org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer=true org.quartz.scheduler.skipUpdateCheck=true org.quartz.scheduler.batchTriggerAcquisitionMaxCount=100 org.quartz.threadPool.threadCount=10 #Configure JDBC-JobStoreTX org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate org.quartz.jobStore.dataSource=myDS org.quartz.jobStore.tablePrefix=QRTZ_ org.quartz.jobStore.isClustered=true org.quartz.jobStore.acquireTriggersWithinLock=true org.quartz.jobStore.clusterCheckinInterval = 30000 #Configure DataSources org.quartz.dataSource.myDS.driver=com.alibaba.druid.proxy.DruidDriver org.quartz.dataSource.myDS.URL=jdbc:wrap-jdbc:filters=default:name=dragoon:jdbc:oracle:thin:@127.0.0.1:1521:test org.quartz.dataSource.myDS.user= org.quartz.dataSource.myDS.password= org.quartz.dataSource.myDS.maxConnections=5 org.quartz.dataSource.myDS.validationQuery=select 1 from dual
org.quartz.scheduler.instanceName 屬性可爲任何值,用在 JDBC JobStore 中來惟一標識實例,可是全部集羣節點中必須相同
org.quartz.jobStore.class屬性爲 JobStoreTX,將任務持久化到數據中。由於集羣中節點依賴於數據庫來傳播 Scheduler 實例的狀態,你只能在使用 JDBC JobStore 時應用 Quartz 集羣。這意味着你必須使用 JobStoreTX 或是 JobStoreCMT 做爲 Job 存儲;你不能在集羣中使用 RAMJobStore
3.實現任務的建立和管理
@Component("schedulerHelper") public class SchedulerHelper { private static final String CONFIG_FILE="quartz-job.properties"; private static final String IDENTITY_JOB_PREFIX="job_"; private static final String IDENTITY_TRIGGER_PREFIX="trigger_"; @Autowired private JobService jobService;//jobService 這個服務是實現管理任務的頁面的服務實現 private Scheduler scheduler; @Autowired private StartJobSchedulerListener startJobSchedulerListener;//實現本身的Scheduler監聽器,程序啓動時,任務沒建立時就建立 /** * tomcat一啓動時,類實例化時就執行 */ public void init() { try{ // 建立一個定時器工廠 StdSchedulerFactory sf = new StdSchedulerFactory(); //初始化quartz-job.properties配置文件 sf.initialize(Thread.currentThread().getContextClassLoader().getResource(CONFIG_FILE).getFile()); scheduler = sf.getScheduler(); //把jobService放到scheduler上下文,job執行是能夠獲取並訪問。 scheduler.getContext().put(SCHEDULER_KEY_JOBSERVICE,jobService); startJobSchedulerListener.setSchedulerHelper(this); //設置本身的監聽器 scheduler.getListenerManager().addSchedulerListener(startJobSchedulerListener); // 啓動定時器 scheduler.start(); logger.info("====================job scheduler start"); }catch(SchedulerException e){ logger.error("error",e); } } /** * 根據jobentity建立並開始任務 */ public boolean createAndStartJob(JobEntity job) { JobDetail jobDetail=generateJobDetail(job); Trigger trigger=generateTriggerBuilder(job).build(); try { scheduler.scheduleJob(jobDetail, trigger); return true; } catch (SchedulerException e) { logger.error("scheduler.scheduleJob",e); return false; } } /** * 清除 */ public void clearAllScheduler() { try { scheduler.clear(); } catch (SchedulerException e) { logger.error("clearAllScheduler",e); } } /** * 根據jobId和類型刪除 */ public boolean removeJob(Long jobId,String jobType) { try { scheduler.deleteJob(getJobKey(jobId,jobType)); return true; } catch (SchedulerException e) { logger.error("removeJob",e); return false; } } /** * 暫停任務 */ public boolean pauseJob(Long jobId,String jobType) { try { scheduler.pauseJob(getJobKey(jobId,jobType)); return true; } catch (SchedulerException e) { logger.error("resumeJob",e); return false; } } /** * 立刻只執行一次任務 */ public boolean executeOneceJob(Long jobId,String jobType) { try { Calendar end=Calendar.getInstance(); TriggerBuilder<SimpleTrigger> simpleTriggerBuilder=TriggerBuilder.newTrigger() .withIdentity(getTriggerKey(jobId,jobType)) .forJob(getJobKey(jobId,jobType)) .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2)); end.add(Calendar.SECOND, 2); simpleTriggerBuilder.startAt(end.getTime()); end.add(Calendar.SECOND, 5); simpleTriggerBuilder.endAt(end.getTime()); JobEntity job=jobService.getJobById(jobId); JobDataMap jobDataMap=new JobDataMap(); jobDataMap.put("jobEntity", job); simpleTriggerBuilder.usingJobData(jobDataMap); Trigger trigger=simpleTriggerBuilder.build(); scheduler.scheduleJob(trigger); return true; } catch (SchedulerException e) { logger.error("executeOneceJob",e); return false; } } /** * 啓動一些scheduler裏沒有的active的jobDetail */ public void createActiveJobFromDB() throws SchedulerException { List<JobEntity> jobs=jobService.getActiveJob(); for(JobEntity job:jobs) { if(scheduler.getJobDetail(getJobKey(job))==null) createAndStartJob(job); } } /** * 得到任務的jobKey */ public static JobKey getJobKey(Long jobId,String jobType) { return new JobKey(IDENTITY_JOB_PREFIX+jobId,IDENTITY_JOB_PREFIX+jobType); } /** * 得到任務的jobKey */ public static JobKey getJobKey(JobEntity job) { return new JobKey(IDENTITY_JOB_PREFIX+job.getJobId(),IDENTITY_JOB_PREFIX+job.getJobType()); } /** * 得到trigger的triggerkey */ public static TriggerKey getTriggerKey(JobEntity job) { return new TriggerKey(IDENTITY_TRIGGER_PREFIX+job.getJobId()+"_"+System.currentTimeMillis(), IDENTITY_TRIGGER_PREFIX+job.getJobType()); } /** * 得到trigger的triggerkey */ public static TriggerKey getTriggerKey(Long jobId,String jobType) { return new TriggerKey(IDENTITY_TRIGGER_PREFIX+jobId+"_"+System.currentTimeMillis(), IDENTITY_TRIGGER_PREFIX+jobType); } public static JobDetail generateJobDetail(JobEntity job) { JobDataMap jobDataMap=new JobDataMap(); jobDataMap.put("jobEntity", job); Class<? extends Job> clazz=null; clazz=BeanJob.class; return JobBuilder.newJob(clazz) .withIdentity(getJobKey(job)) .usingJobData(jobDataMap) .requestRecovery(true).storeDurably(true) .build(); } /** * 根據jobEntity得到trigger */ public static TriggerBuilder<CronTrigger> generateTriggerBuilder(JobEntity job) { TriggerBuilder<CronTrigger> triggerBuilder= TriggerBuilder.newTrigger() .withIdentity(getTriggerKey(job)) .withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpr()) .withMisfireHandlingInstructionDoNothing()); if(job.getSyncBeginTime()!=null) triggerBuilder.startAt(job.getSyncBeginTime()); else triggerBuilder.startNow(); if(job.getSyncEndTime()!=null) triggerBuilder.endAt(job.getSyncEndTime()); return triggerBuilder; } public static JobService getJobService(JobExecutionContext context) { try { return (JobService) context.getScheduler().getContext().get(SchedulerHelper.SCHEDULER_KEY_JOBSERVICE); } catch (SchedulerException e) { logger.error("SchedulerHelper.getJobService",e); return null; } }
4.實現本身的Scheduler監聽器,程序啓動時,建立scheduler裏沒有的active的jobDetail
@Component(value="startJobSchedulerListener") public class StartJobSchedulerListener extends SchedulerListenerSupport { private SchedulerHelper schedulerHelper; @Override public void schedulerStarted() { try { schedulerHelper.createActiveJobFromDB(); } catch (SchedulerException e) { logger.error("createActiveJobFromDB",e); } } public SchedulerHelper getSchedulerHelper() { return schedulerHelper; } public void setSchedulerHelper(SchedulerHelper schedulerHelper) { this.schedulerHelper = schedulerHelper; } }
5.實現的是一個job實例對應一個線程並實現頁面配置對應的哪一個類和方法
public abstract class AbstractEdiJob implements Job { protected JobEntity jobEntity; protected static final Logger logger=LoggerFactory.getLogger(AbstractEdiJob.class); private Long beginTime; @Override public void execute(JobExecutionContext context) throws JobExecutionException { JobService jobService=SchedulerHelper.getJobService(context); preExcute(jobService,context); exeucuteInternal(context); postExcute(jobService,context); } abstract public void exeucuteInternal(JobExecutionContext context); public void preExcute(JobService jobService,JobExecutionContext context) { beginTime=System.currentTimeMillis(); } public void postExcute(JobService jobService,JobExecutionContext context) { //得到最新的jobEntiry jobEntity=jobService.getJobById(jobEntity.getJobId()); if(jobEntity==null) { logger.warn(jobEntity.getJobId()+"job不能存在"); return; } if(context.getFireTime()!=null) jobEntity.setRuntimeLast(context.getFireTime()); if(context.getNextFireTime()!=null) jobEntity.setRuntimeNext(context.getNextFireTime()); /* else jobEntity.setJobStatus();*/ Long times=jobEntity.getRunTimes(); jobEntity.setRunTimes((times==null?0l:times)+1); Long duration=jobEntity.getRunDuration(); jobEntity.setRunDuration((duration==null?0l:duration)+(System.currentTimeMillis()-beginTime)); jobService.updateJob(jobEntity); //jobEntity這裏的改變不能改變JobDetail裏的JobEntity,由於生產的job是JobDetail的JobEntity的複製 } public void setJobEntity(JobEntity jobEntity) { this.jobEntity = jobEntity; } }
/** *執行具體類中的方法 **/ public class BeanJob extends AbstractEdiJob { private static Logger logger=LoggerFactory.getLogger(BeanJob.class); @Override public void exeucuteInternal(JobExecutionContext context) { Object obj=SpringContextUtil.getBean(jobEntity.getJobObject()); try { Method method=obj.getClass().getMethod(jobEntity.getJobMethod()); method.invoke(obj); } catch (SecurityException e) { logger.error("error",e); } catch (NoSuchMethodException e) { logger.error("error",e); } catch (IllegalArgumentException e) { logger.error("error",e); } catch (IllegalAccessException e) { logger.error("error",e); } catch (InvocationTargetException e) { logger.error("error",e); } } }
6.新增一個任務時,數據庫就保存對應的觸發器,變成持久化任務,如圖所示:
1.用StdSchedulerFactory來獲取Scheduler的實例,scheduler有啓動(start)、停止(stop)和暫停(pause)方法。
2.JobDataMap實例,JobDataMap jobDataMap=new JobDataMap();jobDataMap.put("jobEntity", job);在同一任務的屢次執行之間傳遞數據
3.建立JobDetail實例。JobBuilder.newJob(clazz).withIdentity(getJobKey(job)).usingJobData(jobDataMap).requestRecovery(true).storeDurably(true).build();返回JobDetail實例,newJob(clazz)是要執行特定任務的類;withIdentity(getJobKey(job))是job的任務名和組名;usingJobDatausingJobData(jobDataMap)傳輸數據;
4.建立Trigger實例。TriggerBuilder<CronTrigger> triggerBuilder= TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(job))
.withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpr())
.withMisfireHandlingInstructionDoNothing());
withIdentity有標示了觸發器的名稱和組(Quartz調度是經過觸發器的類別來識別不一樣的任務),和withSchedule標示執行的時間表達式
5.最後經過scheduler.scheduleJob()方法調度任務。