一篇搞定---Quartz的基本工作原理和使用

推荐参考文章

通过上述的文章我们可以清晰知道:

任务调度的框架构建是怎么操作的:

(1)首先我们需要定义实现一个定时功能的接口,我们可以称之为Task(或Job),如定时发送邮件的task(Job),重启机器的task(Job),优惠券到期发送短信提醒的task(Job),实现接口如下:

Job进行的是你的任务需要做的事情
在这里插入图片描述

(2)有了任务之后,还需要一个能够实现触发任务去执行的触发器,触发器Trigger最基本的功能是指定Job的执行时间,执行间隔,运行次数等。
==(Trigger)进行的是你的任务需要在什么时候进行触发操作 ==

在这里插入图片描述
(3)有了Job和Trigger后,怎么样将两者结合起来呢?即怎样指定Trigger去执行指定的Job呢?这时需要一个Schedule,来负责这个功能的实现。

将Job和Trigger进行结合起来 使用的是Schedule容器
在这里插入图片描述

因此Quartz的组成部分:
调度器:Scheduler
任务:JobDetail
触发器:Trigger,包括SimpleTrigger和CronTrigger

通俗描述:

  1. JobDetail是一个可执行的工作,它本身可能是有状态的。

  2. Trigger代表一个调度参数的配置,什么时候去调。

  3. scheduler是一个计划调度器容器(总部),容器里面可以盛放众多的JobDetail和trigger,当容器启动后,里面的每个JobDetail都会根据trigger按部就班自动去执行。

  4. 当JobDetail和Trigger在scheduler容器上注册后,形成了装配好的作业(JobDetail和Trigger所组成的一对儿),就可以伴随容器启动而调度执行了。

  5. scheduler是个容器,容器中有一个线程池,用来并行调度执行每个作业,这样可以提高容器效率。

Demo

//创建定时器Job
public class HelloQuartz implements Job {
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDetail detail = context.getJobDetail();
        String name = detail.getJobDataMap().getString("name");
        System.out.println("say hello to " + name + " at " + new Date());
    }
}
public class QuartzTest {
    public static void main(String[] args) {
        try {
            //创建scheduler 容器
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

            //定义一个Trigger
            Trigger trigger = (Trigger) newTrigger().withIdentity("trigger1", "group1") //定义name/group
                    .startNow()//一旦加入scheduler,立即生效
                    .withSchedule(simpleSchedule() //使用SimpleTrigger
                            .withIntervalInSeconds(1) //每隔一秒执行一次
                            .repeatForever()) //一直执行
                    .build();

            Trigger trigger1 = (Trigger) newTrigger().withIdentity("trigger2", "group2") //定义name/group
                    .startNow()//一旦加入scheduler,立即生效
                    .withSchedule(simpleSchedule() //使用SimpleTrigger
                            .withIntervalInSeconds(1) //每隔一秒执行一次
                            .repeatForever()) //一直执行
                    .build();

            //定义一个JobDetail
            JobDetail job = newJob(HelloQuartz.class) //定义Job类为HelloQuartz类,这是真正的执行逻辑所在
                    .withIdentity("jobHello", "groupHello") //定义name/group
                    .usingJobData("name", "quartz") //定义属性
                    .build();
            JobDetail job1 = newJob(HelloQuartz1.class) //定义Job类为HelloQuartz1类,这是真正的执行逻辑所在
                    .withIdentity("job2", "group2") //定义name/group
                    .usingJobData("name2", "quartz2") //定义属性
                    .build();

            //加入这个调度
            scheduler.scheduleJob(job, trigger);
            scheduler.scheduleJob(job1, trigger1);

            //启动之
            scheduler.start();

            //运行一段时间后关闭
            Thread.sleep(10000);
            scheduler.shutdown(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Quartz核心详解

下面就程序中出现的几个参数,看一下Quartz框架中的几个重要参数:

  • Job和JobDetail
  • JobExecutionContext
  • JobDataMap

Trigger、SimpleTrigger、CronTrigger

(1)Job和JobDetail
Job是Quartz中的一个接口,接口下只有execute方法,在这个方法中编写业务逻辑。
接口中的源码:

JobDetail用来绑定Job,为Job实例提供许多属性:

  • name
  • group
  • jobClass
  • jobDataMap

JobDetail绑定指定的Job,每次Scheduler调度执行一个Job的时候,首先会拿到对应的Job,然后创建该Job实例,再去执行Job中的execute()的内容,任务执行结束后,关联的Job对象实例会被释放,且会被JVM GC清除。

为什么设计成JobDetail + Job,不直接使用Job

JobDetail定义的是任务数据,而真正的执行逻辑是在Job中。
这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,Sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。

(2)JobExecutionContext
JobExecutionContext中包含了Quartz运行时的环境以及Job本身的详细数据信息。
当Schedule调度执行一个Job的时候,就会将JobExecutionContext传递给该Job的execute()中,Job就可以通过JobExecutionContext对象获取信息。
主要信息有:

(3)JobExecutionContext
JobDataMap实现了JDK的Map接口,可以以Key-Value的形式存储数据。
JobDetail、Trigger都可以使用JobDataMap来设置一些参数或信息,
Job执行execute()方法的时候,JobExecutionContext可以获取到JobExecutionContext中的信息:
如:

JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class) .usingJobData(“jobDetail1”, “这个Job用来测试的”)
.withIdentity(“job1”, “group1”).build();

Trigger trigger = TriggerBuilder.newTrigger().withIdentity(“trigger1”, “triggerGroup1”)
.usingJobData(“trigger1”, “这是jobDetail1的trigger”)
.startNow()//立即生效
.withSchedule(SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(1)//每隔1s执行一次
.repeatForever()).build();//一直执行

Job执行的时候,可以获取到这些参数信息:

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {

        System.out.println(jobExecutionContext.getJobDetail().getJobDataMap().get("jobDetail1"));
        System.out.println(jobExecutionContext.getTrigger().getJobDataMap().get("trigger1"));
        String printTime = new SimpleDateFormat("yy-MM-dd HH-mm-ss").format(new Date());
        System.out.println("PrintWordsJob start at:" + printTime + ", prints: Hello Job-" + new Random().nextInt(100));


    }

(4)Trigger、SimpleTrigger、CronTrigger

Trigger

Trigger是Quartz的触发器,会去通知Scheduler何时去执行对应Job。

new Trigger().startAt():表示触发器首次被触发的时间;
new Trigger().endAt():表示触发器结束触发的时间;

SimpleTrigger

SimpleTrigger可以实现在一个指定时间段内执行一次作业任务或一个时间段内多次执行作业任务。
下面的程序就实现了程序运行5s后开始执行Job,执行Job 5s后结束执行:

Date startDate = new Date();
startDate.setTime(startDate.getTime() + 5000);

 Date endDate = new Date();
 endDate.setTime(startDate.getTime() + 5000);

        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .usingJobData("trigger1", "这是jobDetail1的trigger")
                .startNow()//立即生效
                .startAt(startDate)
                .endAt(endDate)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(1)//每隔1s执行一次
                .repeatForever()).build();//一直执行

CronTrigger

CronTrigger功能非常强大,是基于日历的作业调度,而SimpleTrigger是精准指定间隔,所以相比SimpleTrigger,CroTrigger更加常用。CroTrigger是基于Cron表达式的,先了解下Cron表达式:
由7个子表达式组成字符串的,格式如下:

[秒] [分] [小时] [日] [月] [周] [年]

Cron表达式的语法比较复杂,

可通过在线生成Cron表达式的工具:Cron生成表达式工具
来生成自己想要的表达式。

下面的代码就实现了每周一到周五上午10:30执行定时任务

public class Scheduler2 {
    public static void main(String[] args) throws SchedulerException, InterruptedException {
        // 1、创建调度器Scheduler
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        // 2、创建JobDetail实例,并与PrintWordsJob类绑定(Job执行内容)
        JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class)
                .usingJobData("jobDetail1", "这个Job用来测试的")
                .withIdentity("job1", "group1").build();
        // 3、构建Trigger实例,每隔1s执行一次
        Date startDate = new Date();
        startDate.setTime(startDate.getTime() + 5000);

        Date endDate = new Date();
        endDate.setTime(startDate.getTime() + 5000);

        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
                .usingJobData("trigger1", "这是jobDetail1的trigger")
                .startNow()//立即生效
                .startAt(startDate)
                .endAt(endDate)
                .withSchedule(CronScheduleBuilder.cronSchedule("* 30 10 ? * 1/5 2018"))
                .build();

        //4、执行
        scheduler.scheduleJob(jobDetail, cronTrigger);
        System.out.println("--------scheduler start ! ------------");
        scheduler.start();
        System.out.println("--------scheduler shutdown ! ------------");

    }
}
Spring Boot Starter Quartz是一个用于Spring Boot应用的轻量级任务调度框架,它允许您利用Quartz库进行定时任务的管理。对于7位cron表达式支持,实际上7位cron表达式的语法是在Quartz标准的6位基础上增加了年份的部分。 标准的Quartz cron表达式格式是: ```text * * * * ? * - - - - - | | | | | 分钟 (0-59) | | | | +--- 小时 (0-23) | | | +---- 日 (1-31) | | +------ 月 (1-12 或者 L W C T Q U V S) | +-------- 星期 (1-7, 或者 # L) +------------- 年 (1970-2099 或者 *) ``` 如果你想在Spring Boot中使用7位cron表达式(如`*/5 * * 1-5 *`),你需要在配置中指定`quartz.cron`属性,并提供完整的表达式,比如: ```java @Configuration @EnableScheduling public class SchedulingConfig { @Value("${myjob.cronExpression:*/5 * * 1-5 *}") private String cronExpression; @Bean(destroyMethod = "shutdown") public org.quartz.Scheduler scheduler() throws SchedulerException { SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() .withIntervalInMinutes(5); return new StdSchedulerFactory().getScheduler() .scheduleJob(jobDetail(), scheduleBuilder.build()); } // ...其他必要的任务配置 private JobDetail jobDetail() { return JobBuilder.newJob(MyJob.class) .withIdentity("myJob", "group1") .usingJobData("cronExpression", cronExpression) .build(); } } ``` 在这个例子中,`${myjob.cronExpression}`变量会被替换为你在application.properties或application.yml文件中设置的值,包含年份部分。注意,这种扩展并不属于Spring Boot Starter Quartz的标准特性,而是需要自定义处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

带着希望活下去

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值