简单了解Quartz

Quartz是一个任务调度框架,主要用来操作定时任务。Quartz主要使用的模式是工厂模式和Builder模式
Quartz的核心主要有:
1. Scheduler: 调度器,主要用来调度任务
2. Job:调度任务,任务的业务逻辑都在这里面编写
3. JobDetail: Job的封装器,用于定义Job的数据
4. Trigger:任务触发器,用于设定触发时间
5. JobBuilder:任务构建器,用于创建JobDetail
6. TriggerBuilder:用于创建Trigger

quartz核心.png

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定义的参数值
        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);

    }
}
执行结果截图.png

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", "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 * * * ?")) //每分钟执行一次
                .build();

        // Tell quartz to schedule the job using our trigger
        scheduler.scheduleJob(job, trigger);

    }
}
cron方式运行结果.png

通过上面的执行日志,我们可以看到Quartz的最终执行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);
        //创建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 不支持(需要自己实现,用分布式锁)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。