1.为什么需要?
由于项目中需要根据配置的参数来动态启用和暂停定时任务。
2.实战代码
实战一: 可以根据数据库时间动态改变但不能停止和启动
import com.xxxx.xxxx.service.WmgMlService;
import com.xxxx.xxxx.util.StringUtils;
import com.xxxx.xxxx.webSocket.XmjgJytsWebSocket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
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.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
/**
* 建议投诉 ---定时任务
* @author wyz
* @create 2019-07-2914:26
*/
@Configuration
@EnableScheduling //开启定时任务
public class ScheduledConfig implements SchedulingConfigurer{
public static Logger logger = LoggerFactory.getLogger(ScheduledConfig.class);
@Autowired
private WmgMlService wmgMlService;
/**
* 获取cron表达式
*
* @param type 配置信息类型
* @param timeType 时间类型 AM:早上 PM:下午
* @return
*/
public String getCron(String type,String timeType) {
String result = "";
List<Map> list = wmgMlService.getXmjgCsConfig(type);
if(null != list && list.size()>0){
if(StringUtils.equal("AM",timeType)){
String amStart = list.get(0).get("amTimeStart").toString();
amStart = amStart.substring(amStart.indexOf(" "),amStart.indexOf(":")).trim();
String amEnd = list.get(0).get("amTimeEnd").toString();
amEnd = amEnd.substring(amEnd.indexOf(" "),amEnd.indexOf(":")).trim();
result ="* * "+amStart+"-"+amEnd+" * * ?";
return result;
}else{
String pmStart = list.get(0).get("pmTimeStart").toString();
pmStart = pmStart.substring(pmStart.indexOf(" "),pmStart.indexOf(":")).trim();
String pmEnd = list.get(0).get("pmTimeEnd").toString();
pmEnd = pmEnd.substring(pmEnd.indexOf(" "),pmEnd.indexOf(":")).trim();
result ="* * "+pmStart+"-"+pmEnd+" * * ?";
return result;
}
}
return result;
}
//定时任务
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(10);
scheduledTaskRegistrar.setScheduler(executorService);
scheduledTaskRegistrar.addTriggerTask(new MyTask("C_WAIT_HANDLE_AM"),new MyTrigger("C_WAIT_HANDLE","AM"));
scheduledTaskRegistrar.addTriggerTask(new MyTask("C_WAIT_HANDLE_PM"),new MyTrigger("C_WAIT_HANDLE","PM"));
scheduledTaskRegistrar.addTriggerTask(new MyTask("S_WAIT_HANDLE_AM"),new MyTrigger("S_WAIT_HANDLE","AM"));
scheduledTaskRegistrar.addTriggerTask(new MyTask("S_WAIT_HANDLE_PM"),new MyTrigger("S_WAIT_HANDLE","PM"));
scheduledTaskRegistrar.destroy();
}
//定义任务线程
class MyTask implements Runnable{
private String taskName;
public MyTask(String name){
this.taskName =name;
}
//业务逻辑
@Override
public void run() {
System.out.println(taskName+"======>执行动态定时任务时间: " + LocalDateTime.now()+",线程名字:"+Thread.currentThread().getName());
boolean result = wmgMlService.isNewCsInfo(1,1);
if(!result){//如果新增信息
XmjgJytsWebSocket.sendInfo("有新增信息");
}
System.out.println("result====>"+result);
}
}
//定义触发器
class MyTrigger implements Trigger{
private String type;
private String timeType;
public MyTrigger(String type,String timeType){
this.type=type;
this.timeType=timeType;
}
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
//每次调度时加载cron表达式
String cron = getCron(type,timeType);
System.out.println("cron====>"+cron);
CronTrigger cronTrigger = new CronTrigger(cron);
return cronTrigger.nextExecutionTime(triggerContext);
}
}
}
实战2:可以暂停并利用多线程实现多个线程启动可停止定时器
import com.xxxx.xxxx.service.WmgMlService;
import com.xxxx.xxxx.util.StringUtils;
import com.xxxx.xxxx.webSocket.XmjgJytsWebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
/**
* 利用线程池实现任务调度
* Task任务调度器可以实现任务的调度和删除
* 原理:
* 实现一个类:ThreadPoolTaskScheduler线程池任务调度器,能够开启线程池进行任务调度
* ThreadPoolTaskScheduler.schedule()方法会创建一个定时计划ScheduleFuture,
* 在这个方法中添加两个参数一个是Runable:线程接口类,和CronTrigger(定时任务触发器)
* 在ScheduleFuture中有一个cancel可以停止定时任务
* <p>
* Scheduled Task是一种轻量级的任务定时调度器,相比于Quartz,减少了很多的配置信息,但是Scheduled Task
* 不适用于服务器集群,引文在服务器集群下会出现任务被多次调度执行的情况,因为集群的节点之间是不会共享任务信息的
* 每个节点的定时任务都会定时执行
* <p>
* 建议投诉-[逾期提醒]和[新增提醒]和[配置提醒时间]功能实现逻辑:
* 1.用户访问建议投诉页面时,触发后台开始定时任务
* 2.用户离开页面时,触发后台停止定时任务
* 3.用户在页面修改参数配置后,触发后台修改定时任务。
*/
@RestController
@EnableScheduling
public class XmjgJytsTaskSchedule {
@Autowired
private WmgMlService wmgMlService;
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
private Map<String, ScheduledFuture<?>> map = new ConcurrentHashMap(); //记录任务
private int csTotal;//投诉建议总数量--作为比较中介 定义为类级全局变量
private int csTotalStop = 0;//停止定时任务是保存的投诉建议总数量
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(20);//设置线程池大小
return threadPoolTaskScheduler;
}
/**
* 1,定义一个方法实现定时任务的启动
* 2,定义一个方法实现用于终止定时任务
* 3,修改定时任务时间:changeCron
*/
/**
* 启动定时器
*
* @return
*/
@RequestMapping("/startTask")
@ResponseBody
public String StartTask(Map<String, CronTrigger> mapMyTask) {
/**
* task:定时任务要执行的方法
* trigger:定时任务执行的时间
*/
endTask();//先停止所有 防止恶意在无限开始 Map过大引发内存溢出
mapMyTask = initMyTask();//初始化Map
if (csTotalStop == 0) {
csTotal = wmgMlService.getCsTotal();
} else {
csTotal = csTotalStop;
}
map.put("C_WAIT_HANDLE_AM", threadPoolTaskScheduler.schedule(new MyOverdueInfoTask("[投诉逾期上午提醒定时器]"), mapMyTask.get("C_WAIT_HANDLE_AM")));
map.put("C_WAIT_HANDLE_PM", threadPoolTaskScheduler.schedule(new MyOverdueInfoTask("[投诉逾期下午提醒定时器]"), mapMyTask.get("C_WAIT_HANDLE_PM")));
map.put("S_WAIT_HANDLE_AM", threadPoolTaskScheduler.schedule(new MyHaveNewInfoTask("[建议未处理上午提醒定时器]"), mapMyTask.get("S_WAIT_HANDLE_AM")));
map.put("S_WAIT_HANDLE_PM", threadPoolTaskScheduler.schedule(new MyHaveNewInfoTask("[建议未处理下午提醒定时器]"), mapMyTask.get("S_WAIT_HANDLE_PM")));
System.out.println("建议投诉监听新消息和逾期提醒开始了!!!时间:" + LocalDateTime.now());
return "startTask";
}
/**
* 停止定时任务
*
* @return
*/
@RequestMapping("/endTask")
@ResponseBody
public String endTask() {
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
if (map.get(key) != null) {
map.get(key).cancel(true);//停止定时任务
}
map.remove(key);
System.out.println(key + "======>定时任务停止,时间:" + LocalDateTime.now());
}
//保存此次暂停的总记录数
csTotalStop = csTotal;
System.out.println("暂停的总记录数为:"+csTotalStop);
return "endTask";
}
/**
* 改变调度的时间
* 步骤:
* 1,先停止定时器
* 2,在启动定时器
*/
// @RequestMapping("/changeTask")
// @ResponseBody
public String changeTask() {
//停止定时器
endTask();
//定义新的执行时间
Map<String, CronTrigger> mapMyTask = initMyTask();//初始化触发器
//启动定时器
StartTask(mapMyTask);
System.out.println("建议投诉监听新消息和逾期提醒修改并启动了!!!时间:" + LocalDateTime.now());
return "changeTask";
}
//定义任务线程--新增信息提醒功能
class MyHaveNewInfoTask implements Runnable {
private String taskName;
public MyHaveNewInfoTask(String name) {
this.taskName = name;
}
//业务逻辑
@Override
public void run() {
System.out.println(taskName + "======>定时任务开始,时间: " + LocalDateTime.now() + ",线程名字:" + Thread.currentThread().getName());
int lastData = wmgMlService.getCsTotal(); //数据库最新的建议投诉总数
int insertSum = 0; //新增的个数
boolean result = false;
if (lastData > csTotal) {//新增数据
insertSum = lastData - csTotal;
csTotal = lastData;
result = true;
} else if (lastData < csTotal) {//删除数据
csTotal = lastData;
}
if (result) {
XmjgJytsWebSocket.sendInfo("您有" + insertSum + "条新信息!");//新增信息提醒
}
System.out.println("result====>" + result);
}
}
//定义任务线程--逾期信息提醒功能
class MyOverdueInfoTask implements Runnable {
private String taskName;
public MyOverdueInfoTask(String name) {
this.taskName = name;
}
//业务逻辑
@Override
public void run() {
System.out.println(taskName + "======>定时任务开始,时间: " + LocalDateTime.now() + ",线程名字:" + Thread.currentThread().getName());
List<Map> result = wmgMlService.getOverTimeInfoTotal();
if (null != result && result.size() > 0) {
String one = result.get(0).get("overTimeTwoTotal").toString();//逾期2天个数
String two = result.get(0).get("overTimeSevenTotal").toString();//逾期2天个数
if (!StringUtils.equal("0", one) && !StringUtils.equal("0", two)) {
XmjgJytsWebSocket.sendInfo("未处理的投诉已经超过2天,请及时处理。\n" +
"未处理的投诉已经超过7天,请及时处理");//逾期信息提醒
} else if (!StringUtils.equal("0", one) || StringUtils.equal("0", two)) {
XmjgJytsWebSocket.sendInfo("未处理的投诉已经超过2天,请及时处理。");//逾期信息提醒
} else if (!StringUtils.equal("0", two) || StringUtils.equal("0", one)) {
XmjgJytsWebSocket.sendInfo("未处理的投诉已经超过7天,请及时处理。");//逾期信息提醒
}
}
}
}
/**
* 获取cron表达式
*
* @param type 配置信息类型
* @param timeType 时间类型 AM:早上 PM:下午
* @param warnType 提醒类型 1为逾期提醒 2为新增提醒
* @return
*/
public String getCron(String type, String timeType, String warnType) {
String result = "";
String warnTimeStr = "-";
if ("1" == warnType) {
warnTimeStr = ",";
}
List<Map> list = wmgMlService.getXmjgCsConfig(type);
if (null != list && list.size() > 0) {
if (StringUtils.equal("AM", timeType)) {
String amStart = list.get(0).get("amTimeStart").toString();
amStart = amStart.substring(amStart.indexOf(" "), amStart.indexOf(":")).trim();
String amEnd = list.get(0).get("amTimeEnd").toString();
amEnd = amEnd.substring(amEnd.indexOf(" "), amEnd.indexOf(":")).trim();
result = "0 * " + amStart + warnTimeStr + amEnd + " * * ?";
return result;
} else {
String pmStart = list.get(0).get("pmTimeStart").toString();
pmStart = pmStart.substring(pmStart.indexOf(" "), pmStart.indexOf(":")).trim();
String pmEnd = list.get(0).get("pmTimeEnd").toString();
pmEnd = pmEnd.substring(pmEnd.indexOf(" "), pmEnd.indexOf(":")).trim();
result = "0 * " + pmStart + warnTimeStr + pmEnd + " * * ?";
return result;
}
}
return result;
}
//初始化定时器任务
private Map<String, CronTrigger> initMyTask() {
Map<String, CronTrigger> mapTrigger = new ConcurrentHashMap();
mapTrigger.put("C_WAIT_HANDLE_AM", new CronTrigger(getCron("C_WAIT_HANDLE", "AM", "1")));//投诉逾期上午定时提醒
mapTrigger.put("C_WAIT_HANDLE_PM", new CronTrigger(getCron("C_WAIT_HANDLE", "PM", "1")));//投诉逾期下午定时提醒
mapTrigger.put("S_WAIT_HANDLE_AM", new CronTrigger(getCron("S_WAIT_HANDLE", "AM", "2")));//建议未处理上午定时提醒
mapTrigger.put("S_WAIT_HANDLE_PM", new CronTrigger(getCron("S_WAIT_HANDLE", "PM", "2")));//建议未处理下午定时提醒
return mapTrigger;
}
}
参考文章:
https://blog.csdn.net/qq_34125349/article/details/77430956
https://www.cnblogs.com/mmzs/p/10161936.html
https://www.cnblogs.com/zt007/p/8954096.html