用Quartz 写定时任务

用Quartz 写定时任务

    Quartz是OpenSymphony开源组织在Job scheduling领域的一个开源项目,是一款清新友好的任务调度框架。

    Quartz两大基本功能是job和SimpleTrigger(作业和触发器)。

    基本组成

    核心的是Scheduler类。

    

    有以下几个相关类:

Scheduler:定时任务调度;

Job:任务类需要实现的接口;

JobDetail:Job的实例,被Scheduler执行的是JobDetail,而不是Job;

Trigger:触发Job的执行;

JobBuilder:定义和创建JobDetail实例的接口;

TriggerBuilder:定义和创建Trigger实例的接口;

作业和触发器,是一对多的关系,每一个Job,都仅对应一个JobDetail。

    不使用配置文件

    作业

    继承Job接口并实现execute方法,或是继承QuartzJobBean并实现executeInternal方法:

public class SimpleQuartzJob implements Job {
 
    public SimpleQuartzJob() {
    }
 
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("In SimpleQuartzJob - executing its JOB at " 
                + new Date() + " by " + context.getTrigger().getName());
    }
}

execute 方法接受一个 JobExecutionContext 对象作为参数,提供了job实例的上下文

    触发器

    通过触发器启动任务:

public void task() throws SchedulerException
{
    // Initiate a Schedule Factory
    SchedulerFactory schedulerFactory = new StdSchedulerFactory();
    // Retrieve a scheduler from schedule factory
    Scheduler scheduler = schedulerFactory.getScheduler();
    long ctime = System.currentTimeMillis(); 

    // Initiate JobDetail with job name, job group, and executable job class
    JobDetail jobDetail = 
        new JobDetail("jobDetail-s1", "jobDetailGroup-s1", SimpleQuartzJob.class);
    // Initiate SimpleTrigger with its name and group name
    SimpleTrigger simpleTrigger = 
        new SimpleTrigger("simpleTrigger", "triggerGroup-s1");
    // set its start up time
    simpleTrigger.setStartTime(new Date(ctime));
    // set the interval, how often the job should run (10 seconds here) 
    simpleTrigger.setRepeatInterval(10000);
    // set the number of execution of this job, set to 10 times. 
    simpleTrigger.setRepeatCount(100);
    /** set the ending time of this job. 
    *   We set it for 60 seconds from its startup time here
    *   Even if we set its repeat count to 10, 
    *   this will stop its process after 6 repeats as it gets it endtime by then.*/
    simpleTrigger.setEndTime(new Date(ctime + 60000L));
    // set priority of trigger. If not set, the default is 5
    simpleTrigger.setPriority(10);
    // schedule a job with JobDetail and Trigger
    scheduler.scheduleJob(jobDetail, simpleTrigger);
    // start the scheduler
    scheduler.start();
}

    Cron触发器

    可使用触发器快捷的调用定时任务(Spring有自身的定时任务cron触发器,类似),Corn包含以下七个字段:

    使用xml配置任务

<bean id="tmptimedtask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
    <property name="targetObject">  
        <bean class="com.timetask.TimeTask" />      <!-- 任务 -->
    </property>  
    <property name="targetMethod" value="run" />      <!-- 作业执行方法(注意:这里不再继承Job类) -->
    <property name="concurrent" value="false" /><!-- 作业不并发调度 -->  
</bean>

<bean id="tmpcronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">  
     <property name="jobDetail" ref="timedtask" />  
     <property name="cronExpression" value="0 0 3 * * ?" />  
</bean>  

<bean id="tmpsimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">  
    <property name="jobDetail" ref="timedtask" />  
    <property name="startDelay" value="0" /><!-- 延迟0秒  --> 
    <property name="repeatInterval" value="5000" /><!-- 每5秒调度一次 -->  
</bean>  

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
    <property name="triggers">  
    <list>  
        <ref bean="simpleTrigger" />  
        <ref bean="cronTrigger" />   
    </list>  
    </property>  
</bean>

    在Springboot中使用Quartz(注解)

    引入依赖:

<dependency>   
    <groupId>org.springframework.boot</groupId>   
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

    写Job:

public class TestQuartz extends QuartzJobBean {
    /**
     * 执行任务
     * @param jobExecutionContext
     * @throws JobExecutionException
     */
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("Test task"+new Date());
    }
}

    配置调度、触发器,这里提供了三种示范:

@Configuration
public class QuartzConfig {
    @Bean(name = "myJob")
        public JobDetail testQuartzDetail(){
            return JobBuilder.newJob(TestQuartz.class)
                .withIdentity("testQuartz","testQuartz_group")
                // 执行中应用发生故障,会重新执行
                .requestRecovery()
                // 即使没有Trigger关联,也不删除该JobDetail,而是将其加入队列,等待一个sched.scheduleJob
                .storeDurably()
                .build();
        }
    
    @Bean(name = "scheduleBuilder")
    public SimpleScheduleBuilder scheduleBuilder(){
       SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
         .withIntervalInSeconds(10)  //设置时间周期单位秒
         //.repeatSecondlyForTotalCount(5);//指定执行次数
         .repeatForever();       //始终执行
       return scheduleBuilder;
    }

    //2.0+ trigger
    @Bean(name = "simpleTrigger")
    public Trigger testQuartzSimpleTrigger(
      @Qualifier("scheduleBuilder")ScheduleBuilder scheduleBuilder,
      @Qualifier("myJob")JobDetail job){
      return TriggerBuilder.newTrigger().forJob(job)
        .withIdentity("testQuartzTrigger","triggerGroup")
        .withSchedule(scheduleBuilder)
        .build();
    }
    
    //Spring2.0之前 CornTrigger    
    @Bean(name = "cornTrigger")
    public CronTriggerFactoryBean CornTrigger(@Qualifier("myJob")JobDetail job) {
      CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
      trigger.setJobDetail(job);
      trigger.setCronExpression("0/10 * * * * ?");
      trigger.setName("cornTrigger");
      return trigger;
    }
    
        //2.0+ cornTrigger
    @Bean(name = "cornTrigger2")
    public Trigger SecondCornTrigger(@Qualifier("myJob")JobDetail job) {
      Trigger trigger=TriggerBuilder.newTrigger().forJob(job)
         .withIdentity("cornTrigger2", "triggerGroup")
         .withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ? *"))
         .startNow()        //其实默认即是startNow()
         .build();
         return trigger;
    }
}

    这样配置好的任务会直接被调度触发,一个JobDetail同时注入了三个Trigger,运行结果是每十秒输出三组数据。

    配置properties:

# 线程调度器实例名
org.quartz.scheduler.instanceName = quartzScheduler
#  线程池的线程数,即最多3个任务同时跑
org.quartz.threadPool.threadCount = 3
# 使用内存存储任务和触发器等信息
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

    配置:

@Configuration  
public class QuartzConfigration {  

    @Autowired  
    private JobFactory jobFactory; 

    @Bean  
    public SchedulerFactoryBean schedulerFactoryBean() {  
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();  
        schedulerFactoryBean.setJobFactory(jobFactory);  
        // 用于quartz集群,QuartzScheduler 启动时更新己存在的Job
        schedulerFactoryBean.setOverwriteExistingJobs(true); 
        schedulerFactoryBean.setStartupDelay(1);  
        return schedulerFactoryBean;  
    }  

    @Bean  
    public Scheduler scheduler() {  
        return schedulerFactoryBean().getScheduler();  
    } 

}

     配置jobFactory:

@Component  
public class JobFactory extends AdaptableJobFactory {       
    @Autowired    
    private AutowireCapableBeanFactory capableBeanFactory;    

    @Override    
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {    
        // 调用父类的方法    
        Object jobInstance = super.createJobInstance(bundle);    
        // 进行注入    
        capableBeanFactory.autowireBean(jobInstance);    
        return jobInstance;    
    }    
}

    注册组件(这里省略了任务类):

@Configuration
public class QuartzJobConfig {      
    /**
     * MethodInvokingJobDetailFactoryBean
     */
    @Bean(name = "myJobBean")    
    public MethodInvokingJobDetailFactoryBean myJobBean(
    MyJob myJob) {
      MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
      jobDetail.setConcurrent(false); 
      jobDetail.setName("general-myJob"); 
      jobDetail.setGroup("general"); 
      jobDetail.setTargetObject(myJob); 
      jobDetail.setTargetMethod("myJobBusinessMethod"); 
      return jobDetail;
    }    
    /**
     * CornTriggerFacyoryBean
     */
    @Bean(name = "myJobTrigger")    
    public CronTriggerFactoryBean myJobTrigger(@Qualifier("myJobBean")
     MethodInvokingJobDetailFactoryBean myJobDetailFactoryBean) {
        CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
        trigger.setJobDetail(myJobDetailFactoryBean.getObject());
        trigger.setCronExpression("0/10 * * * * ?"); 
        trigger.setName("general-myJobTrigger");        
        return trigger;
    }

}

把job和触发器注册到调度器:

@Configuration
public class QuartzConfig {

    /**
     * 调度器工厂Bean
     */
    @Bean(name = "schedulerFactory")    
    public SchedulerFactoryBean schedulerFactory(
    @Qualifier("myFirstExerciseJobTrigger") Trigger myFirstExerciseJobTrigger,                                                 
    @Qualifier("mySecondExerciseJobTrigger") Trigger mySecondExerciseJobTrigger) {
        SchedulerFactoryBean bean = new SchedulerFactoryBean();       
       // 覆盖已存在的任务
        bean.setOverwriteExistingJobs(true);        
       // 延时启动定时任务,避免系统未完全启动却开始执行定时任务的情况
        bean.setStartupDelay(15);       
        // 注册触发器
        bean.setTriggers(myFirstExerciseJobTrigger, mySecondExerciseJobTrigger);       
        return bean;
    }

}

Quartz的其他扩展(待更新)

多线程下的Quartz

Job仓库

Job的Param

//TODO

参考链接:springboot整合定时任务详解IBM DeveloperWorks:用Quartz进行作业调度


2019-06-18鱼鱼

{{blog.title}}

创建于 {{blog.createTimeStr}}   created  by  {{blog.author}} {{tag}}
最后修改于 {{blog.timelineStr}}
修改文档