一、三种定时任务的实现方法
- Java自带的Api java.util.Timer类和java.util.TimerTask类
- Quartz开源框架,功能强大,使用起来稍显复杂
- Spring 3.0以后自带了task 调度工具,比Quartz更加的简单方便,除Spring相关的包外不需要额外的包,而且支持注解和配置文件两种形式
二、SpringTask实践
本篇文章不会介绍基于SpringTask的定时任务基本使用,主要会详细介绍动态更改cron表达式的实现方法。因为我在实际开发过程中需要通过平台能够动态修改cron表达式,并且还要满足更新后的cron表达式实时生效,如果按以往的使用方式,将cron表达式定义成一个常量的话,是无法满足当前的功能需求的
2.1 新cron表达式只能在项目启动时进行更新
这种方式其实也是不能满足我们的要求的,但是可以在一定程度上实现cron表达式动态更新生效的目标
package com.test.testmanagement.config;
import com.test.testmanagement.controller.casemanagementcontroller.InterfaceCaseTestSuiteController;
import com.test.testmanagement.model.interfaceBean.InterfaceCaseTestSuite;
import com.test.testmanagement.service.InterfaceCaseTestSuiteService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* @description:
* @author: XXX
* @time: 2021-02-09 15:42
*/
@Configuration
@EnableScheduling
public class ScheduledConfig implements SchedulingConfigurer {
@Autowired
private TaskScheduler threadPoolTaskScheduler;
@Autowired
private InterfaceCaseTestSuiteService interfaceCaseTestSuiteService;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
try{
//获取所有的设置定时任务的测试集
List<InterfaceCaseTestSuite> interfaceCaseTestSuiteList = interfaceCaseTestSuiteService.findAllInterfaceCaseTestSuiteWithCrontab();
System.out.println("需要执行定时任务的测试集个数为:" + interfaceCaseTestSuiteList.size());
InterfaceCaseTestSuiteController interfaceCaseTestSuiteController = new InterfaceCaseTestSuiteController();
for(InterfaceCaseTestSuite testSuite : interfaceCaseTestSuiteList){
System.out.println(testSuite.getTestSuiteName() + " tab: " + testSuite.getTestSuiteCrontab());
//可以实现动态调整定时任务的执行频率
taskRegistrar.addTriggerTask(
// 1、添加任务内容(Runnable)
// () -> System.out.println("cccccccccccccccc--->" + Thread.currentThread().getId()),
new Runnable() {
@Override
public void run() {
try{
// interfaceCaseTestSuiteController.debugInterfaceCaseTestSuite(testSuite.getId(), testSuite.getTestSuiteName());
}catch (Exception e){
e.printStackTrace();
}
}
},
// 2、设置执行周期(Trigger)
triggerContext -> {
SimpleDateFormat sdf = new SimpleDateFormat();// 格式化时间
sdf.applyPattern("yyyy-MM-dd HH:mm:ss");// a为am/pm的标记
Date date = new Date();// 获取当前时间
System.out.println("现在时间:" + sdf.format(date)); // 输出已经格式化的现在时间(24小时制)
//2.1 从数据库动态获取执行周期
String cron = testSuite.getTestSuiteCronExpression();
System.out.println("cron表达式的值:" + cron);
//2.2 合法性校验.
if (StringUtils.isEmpty(cron)) {
// Omitted Code ..
System.out.println("计划任务为空");
}
//2.3 返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}catch (Exception e){
System.out.println("动态定时任务出现异常!!");
e.printStackTrace();
}
}
}
2.2 新cron表达式实时生效且无需重启工程
下面将要介绍的实现方式,能够保证在不重启工程的情况下实现cron表达式随时更新随时生效
package com.test.testmanagement.controller.casemanagementcontroller;
import com.test.testmanagement.model.interfaceBean.InterfaceCaseTestSuite;
import com.test.testmanagement.service.InterfaceCaseTestSuiteService;
import com.umetrip.qa.model.ApiResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
/**
* @description:
* @author: XXX
* @time: 2021-07-27 09:40
*/
@RestController
@RequestMapping(value = "/api/testsuite/schedule")
public class TestSuiteScheduleDynamicTask {
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
private Map<Integer, ScheduledFuture<?>> testSuiteMap = new HashMap<>();
@Autowired
private InterfaceCaseTestSuiteService interfaceCaseTestSuiteService;
private InterfaceCaseTestSuiteController interfaceCaseTestSuiteController = new InterfaceCaseTestSuiteController();
//实例化一个线程池任务调度类,可以使用自定义的ThreadPoolTaskScheduler
@Bean
@Qualifier("threadPoolTaskScheduler")
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
return new ThreadPoolTaskScheduler();
}
@RequestMapping(value = "/startCron", method = RequestMethod.GET)
public ApiResult startCron(@RequestParam(value = "id") Integer id) {
ApiResult apiResult = new ApiResult();
InterfaceCaseTestSuite testSuite = interfaceCaseTestSuiteService.findByPrimaryKey(id);
String cron = testSuite.getTestSuiteCronExpression();
//接受任务的返回结果
ScheduledFuture future = threadPoolTaskScheduler.schedule(new MyRunnable(testSuite), new CronTrigger(cron));
System.out.println("future: " + future);
System.out.println("DynamicTask.startCron()");
testSuiteMap.put(id, future);
return apiResult;
}
@RequestMapping(value = "/stopCron", method = RequestMethod.GET)
public ApiResult stopCron(@RequestParam(value = "id") Integer id) {
ApiResult apiResult = new ApiResult();
ScheduledFuture futureTemp = testSuiteMap.get(id);
if (futureTemp != null) {
boolean res = futureTemp.cancel(true);
if (res){
apiResult.setCode(200);
apiResult.setResult("定时任务停止成功");
}else {
apiResult.setCode(400);
apiResult.setResult("定时任务停止失败");
}
}else {
apiResult.setCode(200);
apiResult.setResult("定时任务已经停止");
}
System.out.println("DynamicTask.stopCron()");
return apiResult;
}
// @RequestMapping(value = "/changeCron10", method = RequestMethod.GET)
// public String startCron10(@RequestParam(value = "id") Integer id) {
// stopCron(id);// 先停止,在开启.
// ScheduledFuture future = threadPoolTaskScheduler.schedule(new MyRunnable(), new CronTrigger("*/10 * * * * *"));
// System.out.println("DynamicTask.startCron10()");
// return "changeCron10";
// }
@RequestMapping(value = "/changeCron", method = RequestMethod.GET)
public ApiResult changeCron(@RequestParam(value = "id") Integer id) {
ApiResult apiResult = new ApiResult();
try{
InterfaceCaseTestSuite testSuite = interfaceCaseTestSuiteService.findByPrimaryKey(id);
System.out.println("testSuite name: " + testSuite.getTestSuiteName());
stopCron(testSuite.getId());// 先停止,在开启.
String cron = testSuite.getTestSuiteCronExpression();
ScheduledFuture future = threadPoolTaskScheduler.schedule(new MyRunnable(testSuite), new CronTrigger(cron));
//更新或新增数据到map中
testSuiteMap.put(testSuite.getId(), future);
apiResult.setCode(200);
apiResult.setResult("定时任务表达式更新成功并执行");
System.out.println("DynamicTask.changeCron()");
}catch (Exception e){
apiResult.setCode(400);
apiResult.setResult("定时任务表达式更新失败");
}
return apiResult;
}
@RequestMapping(value = "/initTestSuiteScheduledTasks", method = RequestMethod.GET)
public void initTestSuiteScheduledTasks(){
ApiResult apiResult = new ApiResult();
//获取所有的设置定时任务的测试集
List<InterfaceCaseTestSuite> interfaceCaseTestSuiteList = interfaceCaseTestSuiteService.findAllInterfaceCaseTestSuiteWithCrontab();
System.out.println("需要执行定时任务的测试集个数为:" + interfaceCaseTestSuiteList.size());
for(InterfaceCaseTestSuite testSuite : interfaceCaseTestSuiteList) {
System.out.println(testSuite.getTestSuiteName() + " tab: " + testSuite.getTestSuiteCrontab());
changeCron(testSuite.getId());
}
return;
}
private class MyRunnable implements Runnable {
private InterfaceCaseTestSuite testSuite;
public MyRunnable(InterfaceCaseTestSuite testSuite){
this.testSuite = testSuite;
}
@Override
public void run() {
System.out.println("DynamicTask.MyRunnable.run()," + new Date());
try{
interfaceCaseTestSuiteController.debugInterfaceCaseTestSuite(testSuite.getId(), testSuite.getTestSuiteName());
}catch (Exception e){
e.printStackTrace();
}
}
}
}