本篇文章的目的是记录并实现在Spring Boot中,动态设定与执行定时任务。

我的开发项目是 Maven 项目,所以首先需要在 pom.xml 文件中加入相关的依赖。依赖代码如下所示:

<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>RELEASE</version>
</dependency>

下图是定时任务的列表及功能展示。

一般情况下,定时任务列表都是初始化生成,所以此处并无定时任务的新增功能。每个定时任务的操作栏中都有三种操作,分别是  频率设置、启用(禁用)、手动执行。

频率设置:设置定时任务的执行频率,设置成功后,可以重新设置定时任务的执行频率,这个功能是动态设定执行频率的保证。

启用(禁用):控制定时任务的执行状态,定时执行或者不执行。启用前,需先设置定时任务的执行频率。

手动执行:手动调用定时任务的执行方法,无需等到下次执行时间。手动执行前,定时任务的状态应该为启用状态。

在执行频率的设定上,我选择了直接使用Cron表达式,为了简单与方便,我在末端小图标上加了一个链接,点击图标后,便会跳转到在线Cron表达式页面。

<div class="row">
<label class="label col col-3 text-align-right">频率设置<font color="red">*</font>:</label>
<div class="col col-8">
<div class="input-group ">
<input type="text" class="form-control" id="cron" name="cron" th:value="${monitor.cron}" placeholder="点击末端小图标在线获取Cron表达式"/>
<span onclick="getCron()" class="input-group-addon"><i class="fa fa-calendar"></i></span>
</div>
</div>
</div>
//在线获取Cron表达式
function getCron() {
window.open("http://cron.qqe2.com/"); //打开一个新的网页,不会覆盖当前网页
}

在新打开的网页上,根据需求设定执行频率,将生成的Cron表达式复制到文本框中,点击 “确定” 按钮。下面的代码是点击 “确定” 按钮后,后台的处理逻辑。

  @RequestMapping(value = "setFrequencyCron", method = RequestMethod.POST)
@ResponseBody
@OperationLog(success = "设置频率成功", failure = "设置频率失败")
public Json setFrequencyCron(Monitor monitor) {
try {
Monitor m=monitorService.getMonitorById(monitor.getId());
m.setCron(monitor.getCron());
CronSequenceGenerator cronSequenceGenerator = new CronSequenceGenerator(monitor.getCron());
Date currentTime = new Date(); //当前系统时间
Date nextTimePoint = cronSequenceGenerator.next(currentTime); //下次执行时间
Date nextNextTimePoint = cronSequenceGenerator.next(nextTimePoint); //下下次执行时间
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String nextTime=sdf.format(nextTimePoint);
String nextDoubleTme=sdf.format(nextNextTimePoint);
m.setNextTime(nextTime);
m.setNextDoubleTime(nextDoubleTme);
m.setEnable("0"); //设置频率,让其状态变为“禁用”
monitorService.updateMonitor(m);
return Json.ok("频率设置成功");
} catch (Exception e) {
LOGGER.error("频率设置失败: " + e.getMessage(), e);
return Json.fail("频率设置失败");
}
}

根据Cron表达式,使用 Spring 自带的 CronSequenceGenerator 类可以获得下次执行时间和下下次执行时间。每次设定新的执行频率后,该定时任务的状态都会变为“禁用”,需要重新启用,定时任务才能生效。

下面的代码是点击 “启用”或“禁用” 按钮后,后台的处理逻辑。

    @RequestMapping(value = "setEnable", method = {RequestMethod.GET, RequestMethod.POST})
@ResponseBody
@OperationLog(success = "操作成功", failure = "操作失败")
public Json setEnable(Long id, String enable) {
Json json=new Json();
try {
String msg="";
Monitor monitor=monitorService.getMonitorById(id);
monitor.setEnable(enable);
monitorService.updateMonitor(monitor);
if (enable.equals("1")){
msg="启用成功";
}else if (enable.equals("0")){
msg="禁用成功";
} //启用或禁用时,清空redis中的监控信息
redisUtils.remove(KEY); json.setMsg(msg);
json.setSuccess(true);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
return Json.fail("操作失败");
}
return json;
}

在定时任务的执行过程中,为了减少与数据库的交互,所以使用了缓存工具类  RedisUtils ,会将最新的定时任务信息保存到 RedisUtils 中。所以在启用与禁用定时任务时,将会清除以前保存在 RedisUtils 中的定时任务信息,加载最新的定时任务信息。

在启动类的上方加上  @EnableScheduling 注解,该注解的作用是开启Spring Boot对定时任务的支持。

@EnableScheduling
public class DueUIApplication extends AbstractStdApplication {public static void main(String[] args) {
SpringApplication.run(DueUIApplication.class, args);
} }

新建一个定时任务执行类 MonitorTask  ,在该类中加一个用于扫描定时任务的方法,在该方法上方需要加上 @Scheduled 注解,同时需要带上参数,设定扫描频率。

代码如下所示:

@Component
public class MonitorTask extends AbstractStdAction {
private static final Logger LOGGER = Logger.getLogger(MonitorTask.class); @Autowired
private MonitorService monitorService; private String KEY="pbeechina:due:ui:monitor:action"; //redis的key /**
* 每隔一分钟秒扫描一次监控信息
*/
@Scheduled(cron = "0 0/1 * * * ? ")
@Transactional(propagation= Propagation.NOT_SUPPORTED) //不需要事物管理
public void scanMonitor(){
try {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("**********开始扫描监控的定时任务***********");
} List<Monitor> monitorList=null; //预警监控信息 boolean isKey=redisUtils.exists(KEY); //判断key值是否存在
if (isKey){ //key存在,代表监控信息是最新的
monitorList=(List<Monitor>)redisUtils.get(KEY);
}else {
monitorList=monitorService.getMonitorList(); //查询所有已被启用的监控
if (monitorList != null && monitorList.size() > 0){
redisUtils.set(KEY,monitorList, 1,TimeUnit.DAYS); //设置过期时间一天
}
} if (monitorList != null && monitorList.size() > 0){
for (Monitor monitor:monitorList){
if(StringUtils.isNotEmpty(monitor.getCron())){
CronExpression expression = new CronExpression(monitor.getCron());
if(expression.isSatisfiedBy(new Date(System.currentTimeMillis()))){
LOGGER.info("开始执行定时任务...");
monitorService.autoExecute(monitor);
}
}
}
} if (LOGGER.isDebugEnabled()) {
LOGGER.debug("*******扫描结束***********");
}
} catch (Exception e) {
LOGGER.error("监控定时任务扫描失败", e);
}
}
}

至此,Spring Boot动态执行定时任务的功能就实现了。

如何在Spring Boot 中动态设定与执行定时任务的更多相关文章

  1. 如何在Spring boot中修改默认端口

    文章目录 介绍 使用Property文件 在程序中指定 使用命令行参数 值生效的顺序 如何在Spring boot中修改默认端口 介绍 Spring boot为应用程序提供了很多属性的默认值.但是有时 ...

  2. 如何在Spring Boot中使用Cookies

    一. 导读 本文大纲 读取HTTP Cookie 设置HTTP Cookie 读取所有Cookie[] 为Cookie设置过期时间 Https与Cookie HttpOnly Cookie 删除Coo ...

  3. 在Spring Boot中动态实现定时任务配置

    原文路径:https://zhuanlan.zhihu.com/p/79644891 在日常的项目开发中,往往会涉及到一些需要做到定时执行的代码,例如自动将超过24小时的未付款的单改为取消状态,自动将 ...

  4. 如何在Spring Boot应用启动之后立刻执行一段逻辑

    1. 前言 不知道你有没有接到这种需求,项目启动后立马执行一些逻辑.比如简单的缓存预热,或者上线后的广播之类等等.如果你使用 Spring Boot 框架的话就可以借助其提供的接口CommandLin ...

  5. 如何在spring boot中从控制器返回一个html页面?

    项目截图 解决方法 我之前用的@RestController注解,而@RestController这个控制器返回数据而不是视图,改成@Controller 就好了(以下是修改后的) @Controll ...

  6. 如何在 Spring Boot 中禁用 Actuator 端点安全性?

    默认情况下,所有敏感的 HTTP 端点都是安全的,只有具有 ACTUATOR 角色的用户才能访问它们.安全性是使用标准的 HttpServletRequest.isUserInRole 方法实施的. ...

  7. (转)Spring Boot 2 (十):Spring Boot 中的响应式编程和 WebFlux 入门

    http://www.ityouknow.com/springboot/2019/02/12/spring-boot-webflux.html Spring 5.0 中发布了重量级组件 Webflux ...

  8. Spring Boot 2 (十):Spring Boot 中的响应式编程和 WebFlux 入门

    Spring 5.0 中发布了重量级组件 Webflux,拉起了响应式编程的规模使用序幕. WebFlux 使用的场景是异步非阻塞的,使用 Webflux 作为系统解决方案,在大多数场景下可以提高系统 ...

  9. Spring Boot中使用AOP统一处理Web请求日志

    AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是Spring框架中的一个重要内容,它通 ...

随机推荐

  1. Delphi内建异常类 异常处理参考

    标签: delphiexceptionwindowscasting编程integer 2012-05-19 12:53 2579人阅读 评论(0) 收藏 举报 分类: Delphi(96) [详细过程 ...

  2. C#网页数据采集(三)HttpWebRequest

    <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...

  3. phpMailer 手册

    phpMailer5.0.0属性: 英文地址:http://phpmailer.worxware.com/index.php?pg=properties 属性 (v5.0.0) 类型 默认 描述 $P ...

  4. 转-C++之虚函数不能定义成内联函数的原因

    转自:https://blog.csdn.net/flydreamforever/article/details/61429140 在C++中,inline关键字和virtual关键字分别用来定义c+ ...

  5. Tomcat运行错误示例三

    Tomcat运行错误示例三 最近碰到tomcat启动的问题,如图: 以前也碰见过这种情况,这次写的时候忘记加return,所以跳出了错误,加上之后的效果,如图: 参考网址 参考网址

  6. 2. Pycharm的介绍与使用

    使用Python原生IDLE IDLE是Python软件包自带的一个集成开发环境,点击开始-->Python安装包-->IDLE.启动 IDLE 时,会显示>>>,可以在 ...

  7. 7、jmeter-定时器介绍与使用

    jmeter-定时器介绍与使用 固定定时器 Uniform Random Timer Precise Throughput Timer Constant Throughput Timer 高斯随机定时 ...

  8. Java8中Map的遍历方式总结

    在这篇文章中,我将对Map的遍历方式做一个对比和总结,将分别从JAVA8之前和JAVA8做一个遍历方式的对比,亲测可行. public class LambdaMap { private Map< ...

  9. ps--窗口配置

    移动工具设置 v 选择图层自动选择不勾 图层ctrl + 左键 视图设置智能参考线标尺 Ctrl+r 窗口设置 关闭 库 颜色 打开 信息 字符 图层 历史记录 信息 面板选项 鼠标单位 像素 rgb ...

  10. hdu6350 /// tarjan+并查集+组合+最大流思想

    题目大意: 给定n个点 m条边没有重边的仙人掌图(没有一条边会同时存在与两个环 也就是环都是相互独立的) 求任意两点间 i^j^maxflow(i,j)的总和 maxflow为两点间最大流 题解:ht ...