定时任务组件、作业调度程序之Quartz
Quartz
Quartz是功能强大的开源作业调度库,几乎可以集成到任何Java应用程序中。
官网: http://www.quartz-scheduler.org/
文档: http://www.quartz-scheduler.org/documentation/
GitHub: https://github.com/quartz-scheduler/quartz
核心API
Scheduler:任务调度器,使任务和触发器关联,统一进行任务的调度
StdSchedulerFactory:任务调度器工厂,可以创建Scheduler对象
JobDetail:任务对象
JobBuilder:任务构建器,用于创建JobDetail对象
Trigger:触发器对象
TriggerBuilder:触发器构建器,用于创建Trigger对象
JobExecutionContext:任务执行的上下文对象,通过此对象可以获取当前执行任务的相关信息,例如JobDetail、Trigger对象都可以获取到
JobDataMap:保存任务实例的状态信息
RAMJobStore:此类实现了一个利用RAM作为其存储设备的JobStore,访问速度极快,但是数据却易失,如果需要在程序关闭之前保持真正的持久性,则不应使用此JobStore
JobStoreTX:通过JDBC将所有数据保存在数据库中
基本使用
添加依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.2</version>
</dependency>
自定义Job类实现Job接口
@Slf4j
public class MyJob implements Job {
public MyJob() {
log.info("public MyJob() ....");
}
/**
* 执行方法
*
* @param jobExecutionContext 任务执行上下文对象
*/
@Override
public void execute(JobExecutionContext jobExecutionContext) {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
log.info("自定义Job执行: {}", formatter.format(now));
// Quartz提供了相应方法可以在创建任务时设置参数,并且通过提供的上下文对象(JobExecutionContext)来获取参数
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
Set<Map.Entry<String, Object>> entries = jobDataMap.entrySet();
entries.forEach((entry) -> {
String key = entry.getKey();
Object value = entry.getValue();
log.info("key : {}, value : {}", key, value);
});
}
}
启动任务调度
public static void main(String[] args) {
try {
//创建调度器
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//创建任务实例
JobDetail jobDetail = JobBuilder.newJob(MyJob.class).
withIdentity("JobDetail_MyJob","myGroup").
build();
//设置参数,在定时任务执行时可以动态获取参数
jobDetail.getJobDataMap().put("key1", "value1");
jobDetail.getJobDataMap().put("key2", "value2");
//构建cron表达式
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
//构建简单的表达式
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(5).repeatForever();
//创建触发器Trigger
Trigger trigger = TriggerBuilder.newTrigger().
withIdentity("Trigger_MyJob","myGroup").
// withSchedule(simpleScheduleBuilder).
withSchedule(cronScheduleBuilder).
build();
//触发器和任务关联
scheduler.scheduleJob(jobDetail, trigger);
//启动任务调度器
scheduler.start();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
16:29:35.012 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.JobDetail_MyJob', class=cn.ybzy.demo.job.MyJob
16:29:35.012 [DefaultQuartzScheduler_QuartzSchedulerThread] INFO cn.ybzy.demo.job.MyJob - public MyJob() ....
16:29:35.012 [DefaultQuartzScheduler_Worker-2] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.JobDetail_MyJob
16:29:35.012 [DefaultQuartzScheduler_Worker-2] INFO cn.ybzy.demo.job.MyJob - 自定义Job执行: 2021-12-21 04:29:35
16:29:35.012 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
16:29:35.012 [DefaultQuartzScheduler_Worker-2] INFO cn.ybzy.demo.job.MyJob - key : key1, value : value1
16:29:35.012 [DefaultQuartzScheduler_Worker-2] INFO cn.ybzy.demo.job.MyJob - key : key2, value : value2
Spring集成Quartz
定义任务类
//@Component 声明bean对象
public class MyJob {
public void run(){
System.out.println("HHello Quartz");
}
}
配置Quartz
创建application-jobs.xml
配置Quartz参数及任务对象
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--自定义任务对象-->
<bean id="jobDemo" class="cn.ybzy.demo.job.MyJob"></bean>
<!--任务详细对象-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="jobDemo"/>
<property name="targetMethod" value="run"/>
</bean>
<!--触发器:通过cron表达式指定执行的时间-->
<bean id="trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail"/>
<property name="cronExpression">
<value>0/10 * * * * ?</value>
</property>
</bean>
<!--任务调度工厂对象-->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="trigger"></ref>
</list>
</property>
</bean>
</beans>
配置web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:application-jobs.xml</param-value>
</context-param>
</web-app>
动态定时任务
通过JobStoreTX对象将任务相关信息保存在数据库中,这样就可以避免服务重启后任务信息丢失的问题。同时此种方式还支持动态定时任务,例如动态添加定时任务、暂停定时任务、删除定时任务等操作。
添加依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
导入数据表
Quartz针对不同的数据库提供了不同的sql脚本文件
https://github.com/quartz-scheduler/quartz/blob/master/quartz-core/src/main/resources/org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql
MySQL数据库,Quartz提供了一套数据模型(共11张表)用于保存定时任务相关信息
配置application.yml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://IP:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC
定时任务配置类
编写定时任务配置类ScheduleConfig
@Configuration
public class ScheduleConfig {
/**
* 调度器工厂,用于创建调度器对象Scheduler
*
* @param dataSource
* @return
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource);
//quartz参数
Properties prop = new Properties();
prop.put("org.quartz.scheduler.instanceName", "myInstanceName");
prop.put("org.quartz.scheduler.instanceId", "AUTO");
//线程池配置
prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
prop.put("org.quartz.threadPool.threadCount", "20");
prop.put("org.quartz.threadPool.threadPriority", "5");
//JobStore配置
prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
//集群配置
prop.put("org.quartz.jobStore.isClustered", "true");
prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
prop.put("org.quartz.jobStore.misfireThreshold", "12000");
prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
factory.setQuartzProperties(prop);
factory.setSchedulerName("mySchedulerName");
//延时启动
factory.setStartupDelay(3);
factory.setApplicationContextSchedulerContextKey("applicationContextKey");
factory.setOverwriteExistingJobs(true);
//设置自动启动,默认为true
factory.setAutoStartup(true);
return factory;
}
}
自定义Job类
@Slf4j
public class MyJob extends QuartzJobBean {
public MyJob() {
log.info("public MyJob() ....");
}
/**
* 任务触发时执行此方法
*
* @param jobExecutionContext
*/
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) {
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
log.info("自定义Job执行: {}", formatter.format(now));
Object uid = jobExecutionContext.getJobDetail().getJobDataMap().get("uid");
log.info("uid: {}", uid);
}
}
实现各类定时任务
@RestController
@RequestMapping("/quartz")
public class QuartzController {
@Autowired
private Scheduler scheduler;
/**
* 添加定时任务
*
* @param cronExpression
* @return
*/
@PostMapping
public String save(String cronExpression) throws Exception {
String uid = UUID.randomUUID().toString();
//构建job信息
JobDetail jobDetail = JobBuilder.newJob(MyJob.class).withIdentity(uid).build();
jobDetail.getJobDataMap().put("uid", uid);
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression)
.withMisfireHandlingInstructionDoNothing();
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(uid).withSchedule(scheduleBuilder).build();
//关联任务和触发器
scheduler.scheduleJob(jobDetail, trigger);
return "success";
}
/**
* 暂停定时任务
*
* @param uid
* @return
*/
@PutMapping("/pause/{uid}")
public String pause(@PathVariable String uid) throws Exception {
JobKey jobKey = JobKey.jobKey(uid);
scheduler.pauseJob(jobKey);
return "success";
}
/**
* 恢复定时任务
*
* @param uid
* @return
*/
@PutMapping("/resume/{uid}")
public String resume(@PathVariable String uid) throws Exception {
JobKey jobKey = JobKey.jobKey(uid);
scheduler.resumeJob(jobKey);
return "success";
}
/**
* 删除定时任务
*
* @param uid
* @return
*/
@DeleteMapping
public String delete(String uid) throws Exception {
JobKey jobKey = JobKey.jobKey(uid);
scheduler.deleteJob(jobKey);
return "success";
}
/**
* 立即执行定时任务
*
* @param uid
* @return
*/
@PutMapping("/run/{uid}")
public String run(@PathVariable String uid) throws Exception {
JobKey jobKey = JobKey.jobKey(uid);
scheduler.triggerJob(jobKey);
return "success";
}
/**
* 更新定时任务
*
* @param uid
* @param cronExpression
* @return
* @throws Exception
*/
@PutMapping
public String update(String uid, String cronExpression) throws Exception {
TriggerKey triggerKey = TriggerKey.triggerKey(uid);
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression)
.withMisfireHandlingInstructionDoNothing();
//获取触发器对象
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
scheduler.rescheduleJob(triggerKey, trigger);
return "success";
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/136996.html