文章目录
前言
Hi,大家好,我是希留。
在项目的开发工程中,经常有需要定时任务调度的功能场景,比如,定时发送短信、定时抽取数据等。那遇到这种功能的时候应该怎么去做呢?
本篇文章向大家介绍几种创建定时任务的方式。如果对你有帮助的话,还不忘点赞支持一下,感谢!文末附有源码
一、单机环境下创建
1.使用TimerTask创建定时任务
Timer是jdk中提供的一个定时器类,通过该类可以为指定的定时任务进行配置。TimerTask类是一个定时任务类,该类实现了Runnable接口,
缺点是Timer的内部只有一个线程,如果有多个任务的话就会顺序执行,这样我们的延迟时间和循环时间就会出现问题。
public class JobTimerTask {
static long count = 0;
public static void main(String[] args) {
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
count++;
System.out.println(count);
}
};
//创建timer对象设置间隔时间
Timer timer = new Timer();
// 间隔天数
long delay = 0;
// 间隔毫秒数
long period = 1000;
timer.scheduleAtFixedRate(timerTask, delay, period);
}
}
2.使用线程池创建定时任务
ScheduledExecutorService线程池:相对延迟或者周期作为定时任务调度,缺点是没有绝对的日期或者时间。
public class JobScheduledExecutorTask {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello ScheduledExecutorService定时任务!!");
}
};
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
// 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间
service.scheduleAtFixedRate(runnable, 1, 1, TimeUnit.SECONDS);
}
}
3.使用spring内置定时任务@Scheduled 注解
@Schedule注解:配置简单功能较多,如果系统使用单机的话可以优先考虑spring定时器。
@Component
@Configuration //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class ScheduleTask {
@Scheduled(cron = "0/5 * * * * ?") //3.添加定时任务
//@Scheduled(fixedRate=5000) //或直接指定时间间隔,例如:5秒
private void configureTasks() {
System.out.println("执行静态定时任务时间: " + LocalDateTime.now());
}
}
二、分布式环境下创建
1.使用Quartz框架
Quartz是一个开源的任务调度框架。基于定时、定期的策略来执行任务是它的核心功能。
Quartz 的常见集群方案是通过在数据库中配置定时器信息, 以数据库悲观锁的方式达到同一个任务始终只有一个节点在运行。亮点是保证节点高可用 (HA), 如果某一个节点挂了, 其他节点可以顶上。
缺点是同一个任务只能有一个节点运行,其他节点将不执行任务,性能低,资源浪费当碰到大量短任务时,各个节点频繁的竞争数据库锁,节点越多这种情况越严重。性能会很低下。
quartz 的分布式仅解决了集群高可用的问题,并没有解决任务分片的问题,不能实现水平扩展。
下面带大家介绍一下两种整合Quartz框架实现定时任务调度的方式,一种是Spring整合的方式,比较繁琐,但是能更好的掌握原理。一种是SpringBoot整合的方式,使用SpirngBoot自带Quartz插件,可以快速集成。
1.1 Spring集成方式
1.1.1 添加pom依赖
<!-- spring集成quartz定时任务-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
</dependency>
<!-- spring为了整合quartz及其他框架的中间环境包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.2.3.RELEASE</version>
</dependency>
1.1.2 初始化Quartz的表
如果需要做持久化的话,数据肯定是要存在数据库的,Quartz提供了相关的表结构,可以直接到官网下。
-- quartz自带表结构
-- 需要用到定时任务才需要创建
DROP TABLE IF EXISTS `qrtz_blob_triggers`;
DROP TABLE IF EXISTS `qrtz_calendars`;
DROP TABLE IF EXISTS `qrtz_cron_triggers`;
DROP TABLE IF EXISTS `qrtz_fired_triggers`;
DROP TABLE IF EXISTS `qrtz_job_details`;
DROP TABLE IF EXISTS `qrtz_locks`;
DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`;
DROP TABLE IF EXISTS `qrtz_scheduler_state`;
DROP TABLE IF EXISTS `qrtz_simple_triggers`;
DROP TABLE IF EXISTS `qrtz_simprop_triggers`;
DROP TABLE IF EXISTS `qrtz_triggers`;
CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(200) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(120) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
1.1.3 初始化自定义的定时任务表
在自定义一张定时任务表,把所有的定时任务都集中起来,方便进行业务操作管理。
-- 定时任务表结构
DROP TABLE IF EXISTS `schedule_job`;
CREATE TABLE `schedule_job` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
`bean` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'bean名称',
`method` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '方法名',
`params` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '参数',
`cron` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'cron表达式',
`status` tinyint(2) NOT NULL DEFAULT 1 COMMENT '状态。0:运行中;1:已暂停;2:已完成;3:运行失败;',
`remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '定时任务表' ROW_FORMAT = Dynamic;
1.1.4 编写配置类
@Configuration
public class SchedulerConfig {
@Autowired
private TaskSchedulerFactory springJobFactory;
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
// 创建Scheduler的工厂
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource);
factory.setJobFactory(springJobFactory);
// quartz参数
factory.setQuartzProperties(this.convertProp());
factory.setSchedulerName("JavaSjzlScheduler");
// 延时启动 应用启动30秒后
factory.setStartupDelay(30);
factory.setApplicationContextSchedulerContextKey("applicationContextKey");
// 可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
factory.setOverwriteExistingJobs(true);
// 设置自动启动,默认为true
factory.setAutoStartup(true);
return factory;
}
private Properties convertProp() {
// quartz参数,也可以写在配置文件里
Properties prop = new Properties();
// 实例名字 #默认或是自己改名字都行
prop.put("org.quartz.scheduler.instanceName", "JavaSjzlScheduler");
// #如果使用集群,instanceId必须唯一,设置成AUTO
prop.put("org.quartz.scheduler.instanceId", "AUTO");
// 线程池配置
prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
// 并发个数
prop.put("org.quartz.threadPool.threadCount", "10");
// # 设置工作者线程的优先级(最大值10,最小值1,常用值5)
prop.put("org.quartz.threadPool.threadPriority", "5");
// JobStore配置 #存储方式使用JobStoreTX,也就是数据库
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");
// #数据库中quartz表的表名前缀
prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
return prop;
}
}
1.1.5 编写自定义的工厂类
由于定时任务Job对象的实例化过程是在Quartz中进行的,需要把将Job Bean也纳入到Spring容器的管理之中,以便在Spring容器启动后,Scheduler自动开始工作,而在Spring容器关闭前,自动关闭Scheduler。
/**
* @author Java升级之路
* @description 自定义的工厂类 创建job实例并将其纳入到Spring容器的管理之中
* @date 2021/7/1
*/
@Component
public class TaskSchedulerFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
protected Object creatJobInstance(TriggerFiredBundle bundle) throws Exception {
//首先,调用父类的方法创建好quartz所需要的实例
Object jobInstance = super.createJobInstance(bundle);
//然后,使用BeanFactory为创建好的Job实例进行属性自动装配,并将其纳入到Spring容器的管理之中
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
1.1.6 编写一个测试任务调度类
**
* @author Java升级之路
* @description 测试任务调度类
* @date 2021/7/1
*/
@Slf4j
@Component
public class HelloJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
// 获得传入的参数
Object params = jobExecutionContext.getMergedJobDataMap().get(JobConstant.JOB_MAP_KEY);
log.info("helloJob is running params={}, time:{}", params, new Date());
}
}
1.1.7 编写一个任务调度工具类
把创建定时任务封装成一个工具类,方便业务上调用
/**
* @author Java升级之路
* @description 执行任务工具类
* @date 2021/7/1
*/
public class ScheduleUtil {
private final static String JOB_KEY = "JOB_";
/**
* 获取schedulerBean
**/
private final static Scheduler scheduler = SpringContextUtil.getBean(Scheduler.class);
/**
* 创建定时任务
**/
public static void create(Long jobId, Job job) {
try {
//构建job信息
JobDetail jobDetail = JobBuilder.newJob(ScheduleUtil.getJobClass(job.getBean()).getClass())
.withIdentity(getJobKey(jobId))
.build();
//表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCron());
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId))
.withSchedule(scheduleBuilder).build();
// 传入参数
jobDetail.getJobDataMap().put(JobConstant.JOB_MAP_KEY, job.getParams());
scheduler.scheduleJob(jobDetail, trigger);
// 默认创建时任务设置为暂停
ScheduleUtil.pause(jobId);
} catch (SchedulerException e) {
throw new RuntimeException("创建定时任务失败");
}
}
/**
* 暂停定时任务
**/
public static void pause(Long jobId) {
try {
scheduler.pauseJob(getJobKey(jobId));
} catch (SchedulerException e) {
throw new RuntimeException("暂停定时任务失败");
}
}
/**
* 恢复启动定时任务
**/
public static void resume(Long jobId) {
try {
scheduler.resumeJob(getJobKey(jobId));
} catch (SchedulerException e) {
throw new RuntimeException("恢复启动定时任务失败");
}
}
/**
* 更新启动定时任务
**/
public static void update(Long jobId, Job job) {
try {
TriggerKey triggerKey = getTriggerKey(jobId);
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCron());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 更新参数
trigger.getJobDataMap().put(JobConstant.JOB_MAP_KEY, job.getParams());
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
} catch (SchedulerException e) {
throw new RuntimeException("更新定时任务失败");
}
}
/**
* 删除定时任务
**/
public static void delete(Long jobId) {
try {
scheduler.pauseTrigger(getTriggerKey(jobId));
scheduler.unscheduleJob(getTriggerKey(jobId));
scheduler.deleteJob(getJobKey(jobId));
} catch (SchedulerException e) {
throw new RuntimeException("删除定时任务失败");
}
}
public static QuartzJobBean getJobClass(String classname) {
return (QuartzJobBean) SpringContextUtil.getBean(classname);
}
public static JobKey getJobKey(Long jobId) {
return JobKey.jobKey(JOB_KEY + jobId);
}
public static TriggerKey getTriggerKey(Long jobId) {
return TriggerKey.triggerKey(JOB_KEY + jobId);
}
}
1.1.8 编写controller类
编写controller类,提供增删改的相关接口
@Slf4j
@RestController
@RequestMapping(value = "schedule/job")
public class JobController {
@Autowired
private JobService jobService;
/**
* 添加定时任务
* @param job 任务
*/
@PostMapping(value = "add")
public R add(Job job) {
jobService.createJob(job);
return R.ok(null);
}
/**
* 暂停定时任务
* @param id 任务ID
*/
@PostMapping(value = "pause/{id}")
public R pause(@PathVariable Long id) {
jobService.pauseJob(id);
return R.ok(null);
}
/**
* 恢复定时任务
* @param id 任务ID
*/
@PostMapping(value = "resume/{id}")
public R resume(@PathVariable Long id) {
jobService.resumeJob(id);
return R.ok(null);
}
/**
* 更新定时任务
* @param job 任务
*/
@PostMapping(value = "update")
public R update(Job job) {
jobService.updateJob(job);
return R.ok(null);
}
/**
* 删除定时任务
* @param id 任务ID
*/
@PostMapping(value = "delete/{id}")
public R delete(@PathVariable Long id) {
jobService.deleteJob(id);
return R.ok(null);
}
}
1.1.9 编写service类
@Service
public class JobServiceImpl extends ServiceImpl<JobMapper, Job> implements JobService {
@Transactional(rollbackFor = Exception.class)
@Override
public void createJob(Job job) {
job.setStatus(JobConstant.JOB_STATUS_PAUSE);
super.save(job);
ScheduleUtil.create(job.getId(), job);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void pauseJob(Long id) {
Job job = this.checkJobExist(id);
job.setStatus(JobConstant.JOB_STATUS_PAUSE);
super.updateById(job);
ScheduleUtil.pause(id);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void resumeJob(Long id) {
Job job = this.checkJobExist(id);
job.setStatus(JobConstant.JOB_STATUS_RUNNING);
super.updateById(job);
ScheduleUtil.resume(id);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void updateJob(Job job) {
job.setStatus(JobConstant.JOB_STATUS_RUNNING);
super.updateById(job);
ScheduleUtil.update(job.getId(), job);
}
@Transactional(rollbackFor = Exception.class)
@Override
public void deleteJob(Long id) {
super.removeById(id);
ScheduleUtil.delete(id);
}
public Job checkJobExist(Long id) {
Job job = super.getById(id);
if (job == null) {
throw new RuntimeException("不存在的任务ID");
}
return job;
}
}
1.1.10 测试
基本代码已编写完成,开始测试。先使用postman工具调用添加定时任务的接口,新增之前编写的测试定时任务调度类的数据,设置每5秒执行一次,由于代码里写的逻辑是添加的时候只是创建好定时任务数据,并不会执行,如下图所示,成功创建数据。
接着调用启动定时任务接口,在查看控制台输出,每5秒输出一次,证明定时任务调度成功。
在调用暂停定时任务接口,查看控制台输出,发现已没有在输出,证明成功暂停定时任务调度。
1.2 SpringBoot集成方式
使用SpringBoot的集成方式,那两个核心的类就不需要写了,因为 spring-boot-starter-quartz 已经帮我们整理完成。所以就不需要我们手动写配置了,其集成步骤就变成:
pom文件添加依赖 ==》yml文件配置 ==》业务逻辑直接使用
1.2.1 添加pom依赖
<!--spring boot集成quartz定时任务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
1.2.2 yml文件配置
上面介绍spring集成方式的时候quartz参数也是可以写在配置文件里的。
quartz:
#相关属性配置
properties:
org:
quartz:
scheduler:
instanceName: JavaSjzlScheduler
instanceId: AUTO
jobStore:
class: org.quartz.impl.jdbcjobstore.JobStoreTX
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
tablePrefix: QRTZ_
isClustered: true
clusterCheckinInterval: 10000
useProperties: false
threadPool:
class: org.quartz.simpl.SimpleThreadPool
threadCount: 10
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true
#数据库方式
job-store-type: jdbc
1.2.3 业务逻辑直接使用
与spring集成方式相比,springBoot集成方式是自动配置的,但是其他业务逻辑代码还是一样的,这里就不在啰嗦,可以直接使用上面的代码。把SchedulerConfig 配置类注释掉,重启项目就可以了。在调用新增接口,启动接口,查看控制台输出,每隔5秒成功输出。
2.使用xxl-job框架创建
关于使用xxl-job框架创建的方式我们下一篇文章在介绍。敬请期待!
总结
好了,以上就是今天要讲的内容,本文介绍了单机环境和分布式环境下,创建定时任务的几种方式。重点介绍了Spring集成Quartz框架,并持久化定时任务到数据库中。
感谢大家的阅读,如果有什么疑问或者建议,欢迎评论区留下你的见解,喜欢的朋友也可以扫码关注我,更多精彩内容等着你~