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表达式的详解
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 }