本篇博客紧接着上一篇Quartz理论部分

七、使用Quartz

1、入门案例

创建项目(我是参加的是springboot项目),先导入依赖:

        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.3.1</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.1</version>
        </dependency>

编写HelloJob.java 任务类,实现Job接口,重写execute方法:

public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException{
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
        String dateString = dateFormat.format(date);

        System.out.println("名称:" + context.getJobDetail().getKey().getName());
        System.out.println("任务组名称:" + context.getJobDetail().getKey().getGroup());
        System.out.println("任务类:" + context.getJobDetail().getClass().getName());

        System.out.println("运行job时间:" + dateString);
    }
}

在项目main方法中写其余部分代码:

public class HelloSchedulerDemo {
    public static void main(String []args) throws SchedulerException {
        //1 调度器(Scheduler),从工厂获取调度的实例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        //2 任务实例(JobDetail)
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)//加载任务类,与HelloJob绑定,要求HelloJob实现Job接口
                .withIdentity("job1", "group1")//参数1:任务的名称(唯一实例) 参数2:任务组的名称
                .build();
        //3 触发器 Trigger
        SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger")
                .startNow()//马上启动触发器
                //.startAt(date)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5))//永远间隔5s开始
                .build();

        /*System.out.println("名称:" + jobDetail.getKey().getName());
        System.out.println("组的名称:" + jobDetail.getKey().getGroup());
        System.out.println("任务类:" + jobDetail.getJobClass().getName());*/

        // 让调度器关联任务和触发器,保证按照触发器定义的条件执行任务
        scheduler.scheduleJob(jobDetail,trigger);

        //启动
        scheduler.start();

        //结束
        //scheduler.shutdown();
    }
}

运行就可以了。

2、Job和JobDetail介绍

3、JobExecutionContext介绍

  • 当Scheduler调用一个Job时,就回将JobExecutionContext传递给Job的execute()方法
  • Job能通过JobExecutionContext对象访问到Quartz运行时候的环境、Job本身的详细数据信息

4、JobDataMap介绍

(1)使用Map获取

  • 在进行任务调度的时,JobDataMap存储在JobExecutionContext中,易获取
  • JobDataMap可以用来装载任何可序列化的对象,当job实例对象被执行时,这些参数对象会传递给它
  • JobDataMap 实现了JDK的Map接口,还添加了非常方便的方法用来存取基本数据类型

修改代码:

public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException{
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");
        String dateString = dateFormat.format(date);

        System.out.println("名称:" + context.getJobDetail().getKey().getName());
        System.out.println("任务组名称:" + context.getJobDetail().getKey().getGroup());
        System.out.println("任务类:" + context.getJobDetail().getClass().getName());

        //从JobDetail中获取JobDataMap参数信息
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
        String jobDataMapMessage = jobDataMap.getString("message");
        System.out.println("任务数据的参数值:" + jobDataMapMessage);
        
        //获取Trigger对象中获取JobDataMap的数据
        JobDataMap triggerDataMap = context.getTrigger().getJobDataMap();
        String triggerDataMapMessage = triggerDataMap.getString("message");
        System.out.println("触发器数据的参数值:" + triggerDataMapMessage);
        
		//获取Trigger的内容
        TriggerKey triggerKey = context.getTrigger().getKey();
        System.out.println("触发器名称:" + triggerKey.getName() + "       触发器组:" + triggerKey.getGroup());
      
        //获取其他内容
        System.out.println("当前任务的执行时间:" + dateFormat.format(context.getFireTime()));
        System.out.println("下一次执行任务时间:" + dateFormat.format(context.getNextFireTime()));

        //工作job内容
        System.out.println("运行job工作内容:" + dateString);
    
    }
}
public class HelloSchedulerDemo {
    public static void main(String []args) throws SchedulerException {
        //1 调度器(Scheduler),从工厂获取调度的实例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        //2 任务实例(JobDetail)
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)//加载任务类,与HelloJob绑定,要求HelloJob实现Job接口
                .withIdentity("job1", "group1")//参数1:任务的名称(唯一实例) 参数2:任务组的名称
                .usingJobData("message","打印日志")//传递参数,名称message
                .build();
        //3 触发器 Trigger
        SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger")
                .startNow()//马上启动触发器
                //.startAt(date)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatForever().withIntervalInSeconds(5))//永远间隔5s开始
                .usingJobData("message","simple触发器") //传递参数,名称message
                .build();

        /*System.out.println("名称:" + jobDetail.getKey().getName());
        System.out.println("组的名称:" + jobDetail.getKey().getGroup());
        System.out.println("任务类:" + jobDetail.getJobClass().getName());*/

        // 让调度器关联任务和触发器,保证按照触发器定义的条件执行任务
        scheduler.scheduleJob(jobDetail,trigger);

        //启动
        scheduler.start();

        //结束
        //scheduler.shutdown();
    }
}

Quartz定时框架——案例讲解
(2)Job实现类中添加setter方法对应的JobDataMap的键值,Quartz框架默认的JobFactory实现类在初始化job实例对象时,会自动调用这些setter方法
HelloJob.java中添加以下代码:

    private String message;

    public void setMessage(String message) {
        this.message = message;
    }
    
    //从setter方法获得message的值
     System.out.println("参数值:" + message);
     

**注意:**如果遇到同名的key,Trigger中的 .usingJobData(“message”,“simple触发器”)会覆盖JobDetail中的 .usingJobData(“message”,“打印日志”)

5、有状态的Job和无状态的Job

@PersistJobDataAfterExecution 注解的使用
有状态的Job可以理解为多次job调用期间可以持有一些状态信息,这些状态信息存储在JobDataMap中,默认的无状态的job每次调用时都会创建一个新的JobDataMap
(1)修改HelloSchedulerDemo.java
添加 .usingJobData(“count”,0),表示计数器

JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)//加载任务类,与HelloJob绑定,要求HelloJob实现Job接口
                .withIdentity("job1", "group1")//参数1:任务的名称(唯一实例) 参数2:任务组的名称
                .usingJobData("message","打印日志")//传递参数,名称message
                .usingJobData("count", 0)
                .build();

(2) 修改HelloJob.java
添加以下代码:

    private Integer count;

    public void setCount(Integer count) {
        this.count = count;
    }
    
	//输出count
    ++count;//累加count
    //将count存放到JobDataMap中
    context.getJobDetail().getJobDataMap().put("count",count );

此时运行结果,count值都是为1,不会累加,此时job是无状态的

添加注解@PersistJobDataAfterExecution ,此job变为有状态的job

@PersistJobDataAfterExecution // 多次调用Job在时候,会对Job进行持久化,保存一个数据的信息
public class HelloJob implements Job {
...

运行得到新结果,count可以实现累加

6、Trigger介绍

Quartz有一些不同的触发器类型,不过,用得最多的是SimpleTrigger和CronTrigger
(1)jobKey
表示job实例的标识,触发器被触发时,该指定的job实例会被执行
(2)startTime
表示触发的时间表,第一次开始被触发的时间,它的数据类型是java.util.Date
(3)endTime
指定触发器被触发的时间,它的数据类型是java.util.Date

案例:
MyJob.java

public class MyJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        Date date = new Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateString = dateFormat.format(date);

        //工作job内容
        System.out.println("运行job工作内容:" + dateString);

        //获取jobKey startTime endTime
        Trigger trigger = context.getTrigger();
        System.out.println("jobKey的名称:" + trigger.getJobKey().getName() +
                "  jobKey的组名称: " + trigger.getJobKey().getGroup());
        System.out.println("任务开始时间:" + dateFormat.format(trigger.getStartTime()) +
                "   任务结束时间:" + dateFormat.format(trigger.getEndTime()));
    }
}

DemoApplication类

@SpringBootApplication
public class DemoApplication {

    public static void main(String []args) throws SchedulerException {
        //1 调度器(Scheduler),从工厂获取调度的实例
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

        //设置任务开始时间
        Date startDate = new Date();
        startDate.setTime(startDate.getTime() + 3000);
        //设置任务结束时间
         Date endDate = new Date();
        endDate.setTime(endDate.getTime()+10000);

        //2 任务实例(JobDetail)
        JobDetail jobDetail = JobBuilder.newJob(MyJob.class)//加载任务类,与HelloJob绑定,要求HelloJob实现Job接口
                .withIdentity("job1", "group1")//参数1:任务的名称(唯一实例) 参数2:任务组的名称
                .build();

        //3 触发器 Trigger
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger")
                .startAt(startDate)
                .endAt(endDate)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).withRepeatCount(2))  //间隔3s开始重复执行2遍
                .build();

        // 让调度器关联任务和触发器,保证按照触发器定义的条件执行任务
        scheduler.scheduleJob(jobDetail,trigger);

        //启动
        scheduler.start();

        //结束
        //scheduler.shutdown();
    }
}

7、SimpleTrigger触发器

SimpleTrigger的设置和使用是最简单的一种QuartzTrigger,它是为那种需要在特定的日期/时间启动、以一个可能的时间间隔重复执行n次的Job所设计的

注意:

  • SimpleTrigger的属性有:开始时间、结束时间、重复次数、重复的时间间隔
  • 重复次数属性的值可以为0、正整数、或常量SimpleTrigger.REPEAT_INDEFINITELY(反复执行)
  • 重复的时间间隔属性必须大于0或长整型的正整数,以毫秒作为时间单位,当重复的时间间隔为0时,意味着与Trigger同时触发进行
  • 如果有指定结束时间属性,则结束时间属性优先于重复次数属性,好处:当我们需要重复创建一个每隔10秒触发一次指定的结束时间的Trigger,而无需去计算从开始到结束的重复次数,我们只需简单的执行结束时间和使用SimpleTrigger.REPEAT_INDEFINITELY作为重复次数的属性

10、CronTrigger触发器

如果需要像日历那样按日程来触发任务,而不是像SimpleTrigger那样每隔特定的间隔时间触发,CronTrigger通常比SimpleTrigger更有用,因为CronTrigger是基于日历的作业调度器

使用CronTrigger,可以指定例如“每个周五中午”、“每个工作日的9:30”、“从每个周一、周二的上午9:00到10:00之间每间隔5分钟”等日程安排来触发,甚至,先SimpleTrigger一样,CronTrigger也有一个startTime、endTime

官网案例:
http://www.quartz-scheduler.org/documentation/2.3.1-SNAPSHOT/examples/Example3.html

(1)Cron Expressions --Cron 表达式
Cron 表达式被用来配置CronTrigger实例。Cron表达式是一个由7个子表达式组成的字符串,每个子表达式都描述了一个单独的日程细节,用空格隔开,分别表示为

  1. Seconds 秒 0-59 可设置多个,用符号表示:, - * /
  2. Minutes 分钟 0-59 用符号表示:, - * /
  3. Hours 小时 0-23
  4. Day-of-Month 月中的天 1-31
  5. Month 月 1-27或者JAN-DEC 用符号表示:, - * /
  6. Day-of-Week 周中的天 1-7或者SUN-SAT
  7. Year(optional field)年(可选) 用符号表示:, - * /

具体表达式怎么写,可以使用在线Cron表达工具生成http://cron.qqe2.com/

SchedulerFactory sf = new StdSchedulerFactory();
Scheduler sched = sf.getScheduler();

JobDetail job = newJob(SimpleJob.class)
    .withIdentity("job1", "group1")
    .build();

CronTrigger trigger = newTrigger()
    .withIdentity("trigger1", "group1")
    .withSchedule(cronSchedule("0/20 * * * * ?"))
    .build();

sched.scheduleJob(job, trigger);

sched.start();

11、配置、资源SchedulerFactory

一般是一个job一个触发器,如果需要一个更加复杂的触发计划,可以创建多个Trigger并指派它们给同一个job

Scheduler的创建方式
(1)StdSchedulerFactory(默认的SchedulerFactory)

  • 使用一组参数(java.util.properties)来创建和初始化Quartz调度器
  • 配置参数一般存储在quartz.properties文件中
  • 调用getScheduler方法就能创建和初始化调度器对象

八、Quartz监听器

相关文章:

  • 2021-11-19
  • 2021-10-13
  • 2021-07-05
  • 2021-08-03
  • 2022-12-23
  • 2021-11-17
  • 2022-01-07
猜你喜欢
  • 2022-12-23
  • 2021-07-09
  • 2021-10-05
  • 2021-05-14
  • 2021-06-14
  • 2021-12-15
相关资源
相似解决方案