Quartz是一个完全由java编写的开源作业调度框架。
quartz核心概念:
1、调度器 (scheduler):
Quartz框架的核心是调度器。JobDetail和Trigger可以通过Scheduler绑定到一起。
a、通过StdSchedulerFactory来创建
SchedulerFactory sfact=new StdSchedulerFactory();
Scheduler scheduler=sfact.getScheduler();
b、通过DirectSchedulerFactory来创建
DiredtSchedulerFactory factory=DirectSchedulerFactory.getInstance();
Scheduler scheduler=factory.getScheduler();
c、通过SchedulerFactoryBean来创建
SchedulerFactoryBean factory = new SchedulerFactoryBean();
Date schedulerJob(JobDetail,Trigger trigger);返回最近触发的一次时间
void standby()暂时挂起
void shutdown()完全关闭,不能重新启动了
shutdown(true)表示等待所有正在执行的job执行完毕之后,再关闭scheduler
shutdown(false)即直接关闭scheduler
*2、任务(job和jobDetail):
*这个很简单,就是我们自己编写的业务逻辑,交给quartz帮我们执行 。
可以通过实现该就接口来实现我们自己的业务逻辑,该接口只有execute()一个方法,我们可以通过下面的方式来实现Job接口来实现我们自己的业务逻辑。
每次都会直接创建一个JobDetail,同时创建一个Job实例,它不直接接受一个Job的实例,但是它接受一个Job的实现类,通过反射方式来实例一个Job。任务执行结束后,关联的Job对象实例会被释放,且会被JVM GC清除。
通过jobDetailBUilder创建:
JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
.withIdentity(jName, jGroup)
.build();
**3、触发器(trigger):
**简单的讲就是调度作业,什么时候开始执行,什么时候结束执行。
创建方式:
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(tName, tGroup)
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule(cron))
.build();
分为SimpleTrigger和ConTrigger:
SimpleTrigger:
SimpleTrigger可以实现在一个指定时间段内执行一次作业任务或一个时间段内多次执行作业任务
CronTrigger:
CronTrigger功能非常强大,是基于日历的作业调度,而SimpleTrigger是精准指定间隔,所以相比SimpleTrigger,CroTrigger更加常用。CroTrigger是基于Cron表达式进行任务的调度的
其他概念:
监听器顾名思义,就是对事件进行监听并且加入自己相应的业务逻辑,主要有以下三个监听器分别对Job,Trigger,Scheduler进行监听:
JobListener
TriggerListener
SchedulerListener
JobExecutionContext中包含了Quartz运行时的环境以及Job本身的详细数据信息。
当Schedule调度执行一个Job的时候,就会将JobExecutionContext传递给该Job的execute()中,Job就可以通过JobExecutionContext对象获取信息。
quartz配置:
在实例化StdSchedulerFactory的时候可以注册一个全局的监听器到Scheduler中,全局监听器会监听每一个Job和Trigger的触发事件。
全局监听器必选有一个无参的构造函数,并且属性值只能是基本类型(包括String)。
配置例子:
//trigger listener配置
org.quartz.triggerListener.NAME = package.className
org.quartz.triggerListener.NAME.propName = propValue
//job listener配置
org.quartz.jobListener.NAME = package.className
org.quartz.jobListener.NAME.propName = propValue
JobStore是Scheduler在运行时用来存储相关的信息的,比如Job, Trigger。
4.1 RAMJobStore
RAMJobStore实现类是在内存中存储信息的,程序一旦结束便丢失了相关的信息。
4.2 JDBCJobStore和JobStoreTX
JDBCJobStore和JobStoreTX都使用关系数据库来存储Schedule相关的信息。
JobStoreTX在每次执行任务后都使用commint或者rollback来提交更改。
如果在一个标准的独立应用或者在一个没有使用JTA事务管理的应用中使用Quartz,JDBCJobStore是一个不错的选择。
JobStoreTX的配置如下:
4.2.1 org.quartz.jobStore.driverDelegateClass数据库驱动列表
org.quartz.impl.jdbcstore.StdJDBCDelegate 适用于完全兼容JDBC的驱动
org.quartz.impl.jdbcstore.MSSQLDelegate 适用于Miscrosoft SQL Server和Sybase数据库
org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.impl.jdbcjobstore.WebLogicDelegate
org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.impl.jdbcjobstore.oracle.WebLogicOracleDelegate
org.quartz.impl.jdbcjobstore.oracle.weblogic.WebLogicOracleDelegate
org.quartz.impl.jdbcjobstore.CloudscapeDelegate
org.quartz.impl.jdbcjobstore.DB2v6Delegate
org.quartz.impl.jdbcjobstore.DB2v7Delegate
org.quartz.impl.jdbcjobstore.DB2v8Delegate
org.quartz.impl.jdbcjobstore.HSQLDBDelegate
org.quartz.impl.jdbcjobstore.PointbaseDelegate
org.quartz.impl.jdbcjobstore.SybaseDelegate
在JobStore使用JDBCJobStore、JobStoreTX、JobStoreCMT的情况下可以使用Quartz的集群特性,简单的配置如下:
//主要配置
org.quartz.scheduler.instanceName = MyClusteredScheduler
org.quartz.scheduler.instanceId = AUTO
//配置数据池连接
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 25
org.quartz.threadPool.treadPriority = 5
//JobStore配置
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcstore.oracle.OracleDelegate
org.quartz.jobStore.userProperties = true
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
//DataSource数据源配置
org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@localhost:1521:dev
org.quartz.dataSource.myDS.user = quartz
org.quartz.dataSource.myDS.password = quartz
org.quartz.dataSource.myDS.maxConnections = 5
org.quartz.dataSource.myDS.validationQuery=select 0 from dual
第一步:添加pom文件依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
第二步:添加quartz.properties文件
#quartz集群配置
#调度标识名 集群中每一个实例都必须使用相同的名称
org.quartz.scheduler.instanceName=DefaultQuartzScheduler
#ID设置为自动获取 每一个必须不同
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.makeSchedulerThreadDaemon=true
#线程池的实现类(一般使用SimpleThreadPool即可满足需求)
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
#指定在线程池里面创建的线程是否是守护线程
org.quartz.threadPool.makeThreadsDaemons=true
#指定线程数,至少为1(无默认值)
org.quartz.threadPool.threadCount:20
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority:5
#数据保存方式为数据库持久化
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
#表的前缀,默认QRTZ_
org.quartz.jobStore.tablePrefix=QRTZ_
#是否加入集群
org.quartz.jobStore.isClustered=true
# 信息保存时间 默认值60秒
org.quartz.jobStore.misfireThreshold=25000
#DataSource数据源配置 默认用的是c3p0
org.quartz.dataSource.myDS.provider = hikaricp
org.quartz.jobStore.dataSource=myDS
org.quartz.dataSource.myDS.driver = org.postgresql.Driver
org.quartz.dataSource.myDS.URL = jdbc:postgresql://127.0.0.1:5432/postgres
org.quartz.dataSource.myDS.user = postgres
org.quartz.dataSource.myDS.password =
org.quartz.dataSource.myDS.maxConnections = 5
org.quartz.dataSource.myDS.validationQuery=select 0 from dual
第三步,添加config类:
package com.example.studydemo.quartz.config;
import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import java.io.IOException;
import java.util.Properties;
@Configuration
public class QuartzConfig {
// 配置文件路径
private static final String QUARTZ_CONFIG = "/quartz.properties";
/**
* @param buttonJobFactory 为SchedulerFactory配置JobFactory
* @return
* @throws IOException
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(JobFactory buttonJobFactory) throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setJobFactory(buttonJobFactory);
factory.setOverwriteExistingJobs(true);
factory.setAutoStartup(true); // 设置自行启动
factory.setQuartzProperties(quartzProperties());
return factory;
}
/**
* 从quartz.properties文件中读取Quartz配置属性
*
* @return
* @throws IOException
*/
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource(QUARTZ_CONFIG));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
/**
* JobFactory与schedulerFactoryBean中的JobFactory相互依赖,注意bean的名称
* 在这里为JobFactory注入了Spring上下文
*
* @param applicationContext
* @return
*/
@Bean
public JobFactory buttonJobFactory(ApplicationContext applicationContext) {
AutoWiredSpringBeanToJobFactory jobFactory = new AutoWiredSpringBeanToJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
/**
* @author Button
* 为JobFactory注入SpringBean,否则Job无法使用Spring创建的bean
*/
public class AutoWiredSpringBeanToJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
}
第四步,controller层
package com.example.studydemo.quartz.controller;
import com.example.studydemo.quartz.service.QuartzService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class QuartzController {
@Autowired
private QuartzService quartzService;
@GetMapping("/test")
public String test(){
return "test";
}
/**
* 新增任务
*/
@GetMapping("/insert")
public String insertTask(String jName, String jGroup, String tName, String tGroup, String cron) {
quartzService.addJob(jName, jGroup, tName, tGroup, cron);
return "添加成功!";
}
/**
* 暂停任务
*/
@GetMapping("/pause")
public String pauseTask(String jName, String jGroup) {
quartzService.pauseJob(jName, jGroup);
return "暂停成功!";
}
/**
* 继续任务
*/
@GetMapping("/resume")
public String resumeTask(String jName, String jGroup) {
quartzService.resumeJob(jName, jGroup);
return "继续成功!";
}
/**
* 删除任务
*/
@GetMapping("/delete")
public String deleteTask(String jName, String jGroup) {
quartzService.deleteJob(jName, jGroup);
return "删除成功!";
}
}
第五步:添加service层
package com.example.studydemo.quartz.service;
import org.springframework.stereotype.Service;
@Service
public interface QuartzService {
/**
* 新增一个定时任务
* @param jName 任务名称
* @param jGroup 任务组
* @param tName 触发器名称
* @param tGroup 触发器组
* @param cron cron表达式
*/
void addJob(String jName, String jGroup, String tName, String tGroup, String cron);
/**
* 暂停定时任务
* @param jName 任务名
* @param jGroup 任务组
*/
void pauseJob(String jName, String jGroup);
/**
* 继续定时任务
* @param jName 任务名
* @param jGroup 任务组
*/
void resumeJob(String jName, String jGroup);
/**
* 删除定时任务
* @param jName 任务名
* @param jGroup 任务组
*/
void deleteJob(String jName, String jGroup);
}
package com.example.studydemo.quartz.service;
import com.example.studydemo.quartz.job.TestJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@Service
public class QuartzServiceImpl implements QuartzService {
@Qualifier("schedulerFactoryBean")
@Autowired
private Scheduler scheduler;
/**
* 新增一个定时任务
* @param jName 任务名称
* @param jGroup 任务组
* @param tName 触发器名称
* @param tGroup 触发器组
* @param cron cron表达式
*/
@Override
public void addJob(String jName, String jGroup, String tName, String tGroup, String cron) {
try {
JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
.withIdentity(jName, jGroup)
.build();
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(tName, tGroup)
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule(cron))
.build();
scheduler.start();
scheduler.scheduleJob(jobDetail, trigger);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 暂停定时任务
* @param jName 任务名
* @param jGroup 任务组
*/
@Override
public void pauseJob(String jName, String jGroup) {
try {
scheduler.pauseJob(JobKey.jobKey(jName, jGroup));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 继续定时任务
* @param jName 任务名
* @param jGroup 任务组
*/
@Override
public void resumeJob(String jName, String jGroup) {
try {
scheduler.resumeJob(JobKey.jobKey(jName, jGroup));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* 删除定时任务
* @param jName 任务名
* @param jGroup 任务组
*/
@Override
public void deleteJob(String jName, String jGroup) {
try {
scheduler.deleteJob(JobKey.jobKey(jName, jGroup));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
第六步:job类
package com.example.studydemo.quartz.job;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class TestJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("执行力任务");
}
}
第二种方式:
第一步添加依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
第二步:在application.properties文件里添加如下配置
#quartz配置
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://127.0.0.1:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=
spring.quartz.properties.org.quartz.scheduler.instanceName=DefaultQuartzScheduler
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
spring.quartz.properties.org.quartz.scheduler.rmi.export=false
spring.quartz.properties.org.quartz.scheduler.rmi.proxy=false
spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_
spring.quartz.properties.org.quartz.jobStore.isClustered=false
spring.quartz.properties.org.quartz.jobStore.useProperties=false
spring.quartz.properties.org.quartz.jobStore.misfireThreshold=60000
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
spring.quartz.properties.org.quartz.threadPool.threadCount=10
spring.quartz.properties.org.quartz.threadPool.threadPriority=5
spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
spring.quartz.properties.org.quartz.dataSource.myDS.URL=jdbc:postgresql://127.0.0.1:5432/postgres
spring.quartz.properties.org.quartz.dataSource.myDS.user=postgres
spring.quartz.properties.org.quartz.dataSource.myDS.password=
spring.quartz.properties.org.quartz.dataSource.myDS.driver=org.postgresql.Driver
spring.quartz.properties.org.quartz.dataSource.myDS.maxConnections=5
spring.quartz.job-store-type=jdbc
1、为什么设计成JobDetail + Job,不直接使用Job