Quartz框架三大核心:

  1:scheduler

代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。
Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行,例如:如schedulerTest.scheduleJob(jobTest, triggerTest)。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler# getContext()获取对应的SchedulerContext实例。
scheduler 由 scheduler 工厂创建:包括DirectSchedulerFactory 和 StdSchedulerFactory(STD:standard标准的意思)。 第二种工厂 StdSchedulerFactory 使用较多,因为 DirectSchedulerFactory 使用起来不够方便,需要作许多详细的手工编码设置。
scheduler 主要有三种:RemoteMBeanScheduler, RemoteScheduler 和 StdScheduler。
scheduler 除了启动外,scheduler 操作包括查询、设置 scheduler 为 standby 模式、继续、停止。
启动scheduler 非常简单,只需要调用 start() 方法即可。只有在scheduler 有实例或standby 模式才能调用start() 方法,一旦调用shutdown() 方法之后就不能再调用start() 方法。

2:trigger
在 Quartz 中,trigger 是用于定义 Job 何时执行。当用 Scheduler 注册一个 Job 的时候要创建一个 Trigger 与这个 Job 相关联。
Quartz 中主要提供了四种类型的 Trigger:包括SimpleTrigger、CronTirgger//DateIntervalTrigger和 NthIncludedDayTrigger。这四种 trigger 可以满足企业应用中的绝大部分需求。
最常用的是 SimpleTrigger 和 CronTrigger 。
一般来说,如果你需要在一个固定的时间和重复次数或者一个固定的间隔时间,那么 SimpleTrigger 比较合适;
如果你有许多复杂的作业调度,那么 CronTrigger 比较合适。CronTrigger 和 Unix 的 cron 机制基本一样,基于通用的公历,我们需要的只是熟悉cron 表达式的用法。
关于Quartz中时间表达式的设置—–corn表达式:

withIdentity() 给触发器一些属性 比如名字,组名。
startNow() 立刻启动
withSchedule(ScheduleBuilder schedBuilder) 以某种触发器触发。
usingJobData(String dataKey, Boolean value) 给具体job传递参数。

3:JobDetail & Job
jobdetail 就是对job的定义,而job是具体执行的逻辑内容。
具体的执行的逻辑需要实现 job类,并实现execute方法。
这里为什么需要有个JobDetai来作为job的定义,为什么不直接使用job?
解释:如果使用jobdetail来定义,那么每次调度都会创建一个new job实例,这样带来的好处就是任务并发执行的时候,互不干扰,不会对临界资源造成影响。
在线学习Quartz框架和API

实现简单的demo
导入jar包
1 <!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
2 <dependency>
3     <groupId>org.quartz-scheduler</groupId>
4     <artifactId>quartz</artifactId>
5     <version>1.8.6</version>
6 </dependency>
SimpleTrigger
新建任务类
1 import org.quartz.Job;
 2 import org.quartz.JobExecutionContext;
 3 import org.quartz.JobExecutionException;
 4  
 5 //任务类要实现job接口以及重写execute方法
 6 public class jobDemo implements Job {
 7     @Override
 8     public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
 9         System.out.println("这是任务类要做的任务");
10     }
11 }

新建触发类(这里任务调度类也写在一起了)

1 import org.quartz.*;
 2 import org.quartz.impl.StdSchedulerFactory;
 3  
 4 import java.util.Date;
 5  
 6 //触发类,触发方法
 7 public class traggerDemo {
 8     public static void main(String[] args) {
 9         //要构造实例化  第一个是工作名称 第二个是任务组   第三个是任务类
10         JobDetail jobDetail=new JobDetail("工作名称","A",jobDemo.class);
11         //创建触发器   第一个参数是触发器的名称(myTrigger)   第二个参数是执行触发的间隔(无限触发)   第三个参数是间隔的时长(3秒)
12         SimpleTrigger simpleTrigger=new SimpleTrigger("myTrigger",SimpleTrigger.REPEAT_INDEFINITELY,3000);
13         //创建完触发器要设置触发器的开始时间  现在开始
14         simpleTrigger.setStartTime(new Date());
15  
16         //开始实例化调度类的调度工厂
17         SchedulerFactory schedulerFactory=new StdSchedulerFactory();
18         try {
19             //获得调度核心
20             Scheduler scheduler=schedulerFactory.getScheduler();
21             //开始整合任务类和触发类 第一个参数是任务类    第二个参数是触发类
22             scheduler.scheduleJob(jobDetail,simpleTrigger);
23             //执行整合并开始任务
24             scheduler.start();
25             //休眠15秒后关闭
26             Thread.sleep(15000);
27             scheduler.shutdown();
28         } catch (Exception e) {
29             e.printStackTrace();
30         }
31  
32     }
33 }

CronTrigger版

这是任务类

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
 
//还是实现并重写
public class jobDemo implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("这是表达式触发的例子");
    }
}

新建触发类(这里任务调度类也写在一起了)

1 import org.quartz.*;
 2 import org.quartz.impl.StdSchedulerFactory;
 3  
 4 import java.text.ParseException;
 5 import java.util.Date;
 6  
 7 public class triggerDemo {
 8     public static void main(String[] args) {
 9         //这是任务类,分组到B组,名字是ctg
10         JobDetail jobDetail=new JobDetail("ctg","B",jobDemo.class);
11  
12         try {
13             //设置每年每月每日的14:17:00秒触发,这是cron表达式
14             CronTrigger cronTrigger=new CronTrigger("mytrigger2","B","0 17 14 ? * * ");
15             //立刻开启
16             cronTrigger.setStartTime(new Date());
17  
18             SchedulerFactory schedulerFactory=new StdSchedulerFactory();
19             Scheduler scheduler=schedulerFactory.getScheduler();
20             scheduler.scheduleJob(jobDetail,cronTrigger);
21             scheduler.start();
22             Thread.sleep(30000);
23             scheduler.shutdown();
24         } catch (ParseException e) {
25             e.printStackTrace();
26         } catch (SchedulerException e) {
27             e.printStackTrace();
28         } catch (InterruptedException e) {
29             e.printStackTrace();
30         }
31     }
32 }

这是cron表达式的详解

这是在线生成cron表达式的网址

 

spring的任务调度

整体demo结构图

 

 还是要带入jar包

1 <properties>
 2         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 3         <maven.compiler.source>1.7</maven.compiler.source>
 4         <maven.compiler.target>1.7</maven.compiler.target>
 5         <!-- spring版本号 -->
 6         <spring.version>4.2.5.RELEASE</spring.version>
 7     </properties>
 8  
 9     <dependencies>
10         <dependency>
11             <groupId>junit</groupId>
12             <artifactId>junit</artifactId>
13             <version>4.11</version>
14             <scope>test</scope>
15         </dependency>
16  
17         <dependency>
18             <groupId>org.quartz-scheduler</groupId>
19             <artifactId>quartz</artifactId>
20             <version>1.8.6</version>
21         </dependency>
22  
23         <!-- 添加spring核心依赖 -->
24         <dependency>
25             <groupId>org.springframework</groupId>
26             <artifactId>spring-core</artifactId>
27             <version>${spring.version}</version>
28         </dependency>
29  
30         <dependency>
31             <groupId>org.springframework</groupId>
32             <artifactId>spring-web</artifactId>
33             <version>${spring.version}</version>
34         </dependency>
35  
36         <dependency>
37             <groupId>org.springframework</groupId>
38             <artifactId>spring-oxm</artifactId>
39             <version>${spring.version}</version>
40         </dependency>
41  
42         <dependency>
43             <groupId>org.springframework</groupId>
44             <artifactId>spring-tx</artifactId>
45             <version>${spring.version}</version>
46         </dependency>
47  
48         <dependency>
49             <groupId>org.springframework</groupId>
50             <artifactId>spring-jdbc</artifactId>
51             <version>${spring.version}</version>
52         </dependency>
53  
54         <dependency>
55             <groupId>org.springframework</groupId>
56             <artifactId>spring-webmvc</artifactId>
57             <version>${spring.version}</version>
58         </dependency>
59  
60         <dependency>
61             <groupId>org.springframework</groupId>
62             <artifactId>spring-context</artifactId>
63             <version>${spring.version}</version>
64         </dependency>
65  
66         <dependency>
67             <groupId>org.springframework</groupId>
68             <artifactId>spring-context-support</artifactId>
69             <version>${spring.version}</version>
70         </dependency>
71  
72         <dependency>
73             <groupId>org.springframework</groupId>
74             <artifactId>spring-aop</artifactId>
75             <version>${spring.version}</version>
76         </dependency>
77  
78         <dependency>
79             <groupId>org.springframework</groupId>
80             <artifactId>spring-test</artifactId>
81             <version>${spring.version}</version>
82         </dependency>

 

applicationContext.xml
1 <?xml version="1.0" encoding="UTF-8"?>
 2 <beans xmlns="http://www.springframework.org/schema/beans"
 3        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4        xmlns:context="http://www.springframework.org/schema/context"
 5        xmlns:aop="http://www.springframework.org/schema/aop"
 6        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
 7        xsi:schemaLocation="http://www.springframework.org/schema/beans
 8            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
 9            http://www.springframework.org/schema/context
10            http://www.springframework.org/schema/context/spring-context-3.2.xsd
11            http://www.springframework.org/schema/aop
12            http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
13            http://www.springframework.org/schema/tx
14            http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"
15        xmlns:p="http://www.springframework.org/schema/p"
16 >
17  
18     <!-- Enables the Spring Task @Scheduled programming model -->
19     <!-- 开启定时任务 -->
20     <task:annotation-driven />
21     <!--spring扫描全部包的注解加入到Spring容器内-->
22     <context:component-scan base-package="com.bdqn.text" />
23  
24  
25 </beans>

任务触发调度类

1 package com.bdqn.text;
 2  
 3 import org.springframework.scheduling.annotation.Scheduled;
 4 import org.springframework.stereotype.Component;
 5 //定义一个bean名叫ssaa方便后续调用
 6 @Component("ssaa")
 7 public class SpringCronDemo1 {
 8  
 9     @Scheduled(cron = " * * * ? * * ")
10     public void show(){
11         System.out.println("这是Spring的Quartz整合测试");
12     }
13 }

测试方法

1 package com.bdqn.text;
 2  
 3 import org.springframework.context.ApplicationContext;
 4 import org.springframework.context.support.ClassPathXmlApplicationContext;
 5  
 6 public class Text {
 7     public static void main(String[] args) {
 8         ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
 9         applicationContext.getBean("ssaa",SpringCronDemo1.class).show();
10     }
11 }

 

项目中出现的问题:
cron表达式怎么写?
答:这个问题,有点尴尬,本来quartz框架用起来就很简单,重点都是在于cron表达式如何写。所以大家还是多google,这里给个地址,我当时看的一篇专栏。
https://zhuanlan.zhihu.com/p/35629505
如何禁止并发执行?
答:项目中出现了一种情况,本来job执行时间只需要10s,但是由于数据库量增大之后,执行时间变成了60s,而我设置的间隔时间是30s,这样就会出现上次任务还没执行完成,下次任务就开始执行了。所以,在这种情况下,我们要禁止quart的并发操作。

2种方式:

spring中将job的concurrent属性设置为false。默认是true 如下:
1  <bean id="scheduleJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
2         <property name="targetObject" ref="scheduleBusinessObject"/>
3         <property name="targetMethod" value="doIt"/>
4         <property name="concurrent" value="false"/>
5     </bean>

 

job类上加上注解@DisallowConcurrentExecution。
1 @DisallowConcurrentExecution
 2 public class HelloQuartz implements Job {
 3 
 4     @Override
 5     public void execute(JobExecutionContext jobExecutionContext) {
 6         JobDetail detail = jobExecutionContext.getJobDetail();
 7         String name = detail.getJobDataMap().getString("name");
 8         System.out.println("my job name is  " + name + " at " + new Date());
 9 
10     }
11 }

 

注意:@DisallowConcurrentExecution是对JobDetail实例生效,如果一个job类被不同的jobdetail引用,这样是可以并发执行。
1 package demos;
 2 
 3 import org.quartz.DisallowConcurrentExecution;
 4 import org.quartz.Job;
 5 import org.quartz.JobExecutionContext;
 6 import org.quartz.JobExecutionException;
 7 
 8 import java.text.SimpleDateFormat;
 9 import java.util.Date;
10 
11 /**
12  * @Description: 自定义任务
13  * @date 2021-11-11 23:13
14  */
15 @DisallowConcurrentExecution   // 禁止并发执行,防止间隔时间过短,上次任务还没执行完,下次任务就开始执行了。
16 public class HelloJob implements Job {
17     public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
18         //打印当前的执行时间,格式为:2017-09-06 00:00:00
19         Date date = new Date();
20         SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
21         System.out.println("当前的时间为(HelloJob):" + sf.format(date));
22         //编写具体的业务逻辑
23         System.out.println("Hello Job!");
24     }
25 }

 

1 package demos;
 2 
 3 import org.quartz.*;
 4 import org.quartz.impl.StdSchedulerFactory;
 5 
 6 import java.text.SimpleDateFormat;
 7 import java.util.Date;
 8 
 9 /**
10  * @Description: 任务调度类
11  * @date 2021-11-11 23:16
12  */
13 public class HelloScheduler {
14     public static final String JOB_NAME = "myjob";
15     public static final String JOB_GROUP = "group1";
16     public static final String TRIGGER_NAME = "myTrigger";
17     public static final String TRIGGER_GROUP = "group1";
18 
19     public static void main(String[] args) throws SchedulerException {
20         /**
21          * JobDetail:用来绑定Job,并且在job执行的时候携带一些执行的信息
22          */
23         //创建一个JobDetail实例,将该实例与HelloJob Class绑定
24         JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity(JOB_NAME, JOB_GROUP).build();
25         /**
26          * Trigger:用来触发job去执行的,包括定义了什么时候去执行,
27          * 第一次执行,是否会一直重复地执行下去,执行几次等
28          */
29         //创建一个Trigger实例,定义该job立即执行,并且每隔2秒钟重复执行一次,直到程序停止
30         /**
31          * trigger通过builder模式来创建,TriggerBuilder.newTrigger()
32          * withIdentity():定义一个标识符,定义了组
33          * startNow():定义现在开始执行,
34          * withSchedule(SimpleScheduleBuilder.simpleSchedule():withSchedule也是builder模式创建
35          *.withIntervalInSeconds(2).repeatForever()):定义了执行频度:每2秒钟执行一次,不间断地重复执行
36          * build():创建trigger
37          */
38 
39         Trigger trigger = TriggerBuilder.newTrigger()
40                 .withIdentity(TRIGGER_NAME,TRIGGER_GROUP).startNow()
41                 .withSchedule(SimpleScheduleBuilder.simpleSchedule()
42                         .withIntervalInSeconds(2).repeatForever()).build();
43 
44         //创建scheduler实例:
45         /**
46          * scheduler区别于trigger和jobDetail,是通过factory模式创建的
47          */
48         //创建一个ScheduleFactory
49         SchedulerFactory sfact = new StdSchedulerFactory();
50         Scheduler scheduler = sfact.getScheduler();
51         scheduler.start();
52 
53         //打印当前时间
54         Date date = new Date();
55         SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
56         System.out.println("当前的时间为(HelloScheduler):" + sf.format(date));
57 
58         //需要将jobDetail和trigger传进去,并将jobDetail和trigger绑定在一起。
59         scheduler.scheduleJob(jobDetail,trigger);
60     }
61 }

 

1 package demos;
 2 
 3 import org.quartz.*;
 4 import org.quartz.impl.StdSchedulerFactory;
 5 
 6 import java.text.SimpleDateFormat;
 7 import java.util.Date;
 8 
 9 /**
10  * @Description: 任务调度类
11  * @date 2021-11-11 23:16
12  */
13 public class HelloScheduler2 {
14     public static final String JOB_NAME = "myjob";
15     public static final String JOB_GROUP = "group1";
16     public static final String TRIGGER_NAME = "myTrigger";
17     public static final String TRIGGER_GROUP = "group1";
18 
19 
20     public static void main(String[] args) throws SchedulerException {
21         /**
22          * JobDetail:用来绑定Job,并且在job执行的时候携带一些执行的信息
23          */
24         //创建一个JobDetail实例,将该实例与HelloJob Class绑定
25         JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity(JOB_NAME, JOB_GROUP).build();
26         /**
27          * Trigger:用来触发job去执行的,包括定义了什么时候去执行,
28          * 第一次执行,是否会一直重复地执行下去,执行几次等
29          */
30 
31         // 创建cron表达式
32         Trigger trigger = TriggerBuilder.newTrigger()
33                 .withIdentity(TRIGGER_NAME,TRIGGER_GROUP).startNow()
34                 .withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 8-20 * * ?")).build(); // // 每天8:00-20:00,每隔1分钟执行一次
35 
36         //创建scheduler实例:
37         /**
38          * scheduler区别于trigger和jobDetail,是通过factory模式创建的
39          */
40         //创建一个ScheduleFactory
41         SchedulerFactory sfact = new StdSchedulerFactory();
42         Scheduler scheduler = sfact.getScheduler();
43         scheduler.start();
44 
45         //打印当前时间
46         Date date = new Date();
47         SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
48         System.out.println("当前的时间为(HelloScheduler):" + sf.format(date));
49 
50         //需要将jobDetail和trigger传进去,并将jobDetail和trigger绑定在一起。
51         scheduler.scheduleJob(jobDetail,trigger);
52     }
53 }