Quartz集成springMVC 的方案二(持久化任务、集群和分布式)

Quartz是一个开放源码项目,专注于任务调度器,提供了极为广泛的特性如持久化任务,集群和分布式任务等。 Quartz核心是调度器,还采用多线程管理。

 1.持久化任务:当应用程序停止运行时,所有调度信息不被丢失,当你重新启动时,调度信息还存在,这就是持久化任务。

 2.集群和分布式处理:当在集群环境下,当有配置Quartz的多个客户端时(节点),采用Quartz的集群和分布式处理时,我们要了解几点好处 1) 一个节点无法完成的任务,会被集群中拥有相同的任务的节点取代执行。2) Quartz调度是通过触发器的类别来识别不同的任务,在不同的节点定义相同的触发器的类别,这样在集群下能稳定的运行,一个节点无法完成的任务,会被集群中拥有相同的任务的节点取代执行。3)分布式 体现在 当相同的任务定时在一个时间点,在那个时间点,不会被两个节点同时执行。

 Quartz的 Task(11 张表)实例化采用数据库存储,基于数据库引擎及 High-Available 的策略(集群的一种策略)自动协调每个节点的 Quartz。

 
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任务要做什么,新建了两个类和方法。

import org.springframework.stereotype.Component;

@Component("quartzJobA")
public class Data2ServiceImpl {

    public void run() {
        System.out.println("=============Data2ServiceImpl=========");
        
    }
}

@Component("quartzJobB")
public class DataServiceImpl {

  
    public void test() {
        System.out.println("=============DataServiceImpl=========");
        
    }

}

2.Quartz 调度任务所需的配置文件 quartz-job.properties

#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;
        }
    }
    
@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()方法调度任务。 

原文地址:https://www.cnblogs.com/koal/p/4982778.html