在我们平时开发的项目中,定时任务基本属于必不可少的功能,那大家都是怎么做的呢?但我知道的大多都是静态定时任务实现。

基于注解来创建定时任务非常简单,只需几行代码便可完成。实现如下:

@Configuration
@EnableScheduling
public class SimpleScheduleTask { //10秒钟执行一次
@Scheduled(cron = "0/10 * * * * ?")
private void tasks() {
System.out.println("【定时任务】 每10秒执行一次!");
}
}

Cron表达式参数分别表示(从左到右):
秒(0~59) 如0/5表示每5秒
分(0~59)
时(0~23)
日(0~31) 月的某一天
月(0~11)
周几( 可填1-7 或 SUN/MON/TUE/WED/THU/FRI/SAT)

就上面几行代码,就能搞定一个定时任务。显然,使用Scheduled 确实特别的方便,但有很大的缺点和局限,就是当我们调整了执行计划的时间时,需要重启服务才能生效,这就有些不方便。为了达到实时生效的效果,可以通过数据库来动态实现定时任务。

 

基于数据库的动态定时任务实现

将定时任务配置在数据库,启动项目的时候,用mybatis读取数据库,实例化对象,并设定定时任务。如果需要新增,减少,修改定时任务,仅需要修改数据库资料,并重启项目即可,无需改代码。

@Lazy(value = false)
@Component
public class ScheduleTask implements SchedulingConfigurer { protected static Logger logger = LoggerFactory.getLogger(ScheduleTask.class);
private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Autowired
private ScheduleTaskMapper scheduleTaskMapper; @Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
List<ScheduleTask> tasks = getAllScheduleTasks();
logger.info("【定时任务启动】 启动任务数:"+tasks.size()+"; time="+sdf.format(new Date())); //校验数据
checkDataList(tasks);
//通过校验的数据执行定时任务
int count = 0;
if(tasks.size()>0) {
for (int i = 0; i < tasks.size(); i++) {
try {
taskRegistrar.addTriggerTask(getRunnable(tasks.get(i)), getTrigger(tasks.get(i)));
count++;
} catch (Exception e) {
logger.error("task start error:" + tasks.get(i).getClassName() + ";" + tasks.get(i).getMethodName() + ";" + e.getMessage());
}
}
}
logger.info("started task number="+count+"; time="+sdf.format(new Date()));
}; /**
* 获取要执行的所有任务
* @return
*/
private List<ScheduleTask> getAllScheduleTasks() {
ScheduleTaskExample example=new ScheduleTaskExample();
example.createCriteria().andIsDeleteEqualTo((byte) 0);
return scheduleTaskMapper.selectByExample(example);
} /**
* 获取Runnable
*
* @param task
* @return
*/
private Runnable getRunnable(ScheduleTask task){
return new Runnable() {
@Override
public void run() {
try {
Object obj = SpringUtil.getBean(task.getClassName());
Method method = obj.getClass().getMethod(task.getMethodName(),null);
method.invoke(obj);
} catch (InvocationTargetException e) {
logger.error("refect exception:"+task.getClassName()+";"+task.getMethodName()+";"+ e.getMessage());
} catch (Exception e) {
logger.error(e.getMessage());
}
}
};
} /**
* 获取Trigger
*
* @param task
* @return
*/
private Trigger getTrigger(ScheduleTask task){
return new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
//将Cron 0/1 * * * * ?
CronTrigger trigger = new CronTrigger(task.getCron());
Date nextExec = trigger.nextExecutionTime(triggerContext);
return nextExec;
}
};
} /**
* 校验数据
*
* @param list
* @return
*/
private List<ScheduleTask> checkDataList(List<ScheduleTask> list) {
String msg="";
for(int i=0;i<list.size();i++){
if(!checkOneData(list.get(i)).equalsIgnoreCase("ok")){
msg+=list.get(i).getTaskName()+";";
list.remove(list.get(i));
i--;
};
}
if(!StringUtils.IsEmpty(msg)){
msg="未启动的任务:"+msg;
logger.error(msg);
}
return list;
} /**
* 按每一条校验数据
*
* @param task
* @return
*/
private String checkOneData(ScheduleTask task){
String result="ok";
Class cal= null;
try {
cal = Class.forName(task.getClassName());
Object obj =SpringUtil.getBean(cal);
Method method = obj.getClass().getMethod(task.getMethodName(),null);
String cron=task.getCron();
if(StringUtils.isBlank(cron)){
result="no found the cron:"+task.getTaskName();
logger.error(result);
}
} catch (ClassNotFoundException e) {
result="not found the class:"+task.getClassName()+ e.getMessage();
logger.error(result);
} catch (NoSuchMethodException e) {
result="not found the method:"+task.getClassName()+";"+task.getMethodName()+";"+ e.getMessage();
logger.error(result);
} catch (Exception e) {
logger.error(e.getMessage());
}
return result;
}
}

  

数据库配置

 

运行的结果

 

这样我们可以通过直接修改数据库,执行周期就会改变,并且不需要我们重启应用,十分方便。

推荐阅读:

Java中大量if...else语句的消除替代方案

Java8中遍历Map的常用四种方式

推荐一些MySQL优化技巧,效率提升不止十倍!

扫码关注公众号,发送关键词获取相关资料:
  1. 发“Springboot”领取电商项目实战源码;

  2. 发“SpringCloud”领取学习实战资料;

 

SpringBoot基于数据库的定时任务实现的更多相关文章

  1. SpringBoot基于数据库的定时任务统一管理

    定时任务1 import lombok.extern.slf4j.Slf4j; /** * @author Created by niugang on 2019/12/24/15:29 */ @Slf ...

  2. SpringBoot基于数据库实现简单的分布式锁

    本文介绍SpringBoot基于数据库实现简单的分布式锁. 1.简介 分布式锁的方式有很多种,通常方案有: 基于mysql数据库 基于redis 基于ZooKeeper 网上的实现方式有很多,本文主要 ...

  3. springboot 基于@Scheduled注解 实现定时任务

    前言 使用SpringBoot创建定时任务非常简单,目前主要有以下三种创建方式: 一.基于注解(@Scheduled) 二.基于接口(SchedulingConfigurer) 前者相信大家都很熟悉, ...

  4. SpringBoot整合mybatis、shiro、redis实现基于数据库的细粒度动态权限管理系统实例

    1.前言 本文主要介绍使用SpringBoot与shiro实现基于数据库的细粒度动态权限管理系统实例. 使用技术:SpringBoot.mybatis.shiro.thymeleaf.pagehelp ...

  5. 四、springBoot 优雅的创建定时任务

    前言 好几天没写了,工作有点忙,最近工作刚好做一个定时任务统计的,所以就将springboot 如何创建定时任务整理了一下. 总的来说,springboot创建定时任务是非常简单的,不用像spring ...

  6. SpringBoot2.0整合mybatis、shiro、redis实现基于数据库权限管理系统

    转自https://blog.csdn.net/poorcoder_/article/details/71374002 本文主要介绍使用SpringBoot与shiro实现基于数据库的细粒度动态权限管 ...

  7. SpringBoot基于websocket的网页聊天

    一.入门简介正常聊天程序需要使用消息组件ActiveMQ或者Kafka等,这里是一个Websocket入门程序. 有人有疑问这个技术有什么作用,为什么要有它?其实我们虽然有http协议,但是它有一个缺 ...

  8. 基于数据库、redis和zookeeper实现的分布式锁

    基于数据库 基于数据库(MySQL)的方案,一般分为3类:基于表记录.乐观锁和悲观锁 基于表记录 用表主键或表字段加唯一性索引便可实现,如下: CREATE TABLE `database_lock` ...

  9. 为什么要用hibernate 与基于数据库表结构的项目开发

    最近开始学习hibernate,其实并不知道要学习什么,有什么用.后来问了一下同事,他就说快捷方便简单,很多事情不用自己做他会帮你做好,但是我觉得不应该是这样的,于是我就去搜了一下,就搜到了一篇帖子, ...

随机推荐

  1. 微信小程序图片设置圆角进入页面闪动

    transform变形 当我们通过某些行为触发页面进行大面积绘制的时候,浏览器由于没有事先准备,应付渲染够呛,于是掉帧,于是卡顿.而will-change则是真正的行为触发之前告诉浏览器:“我待会儿就 ...

  2. jvm(n):JVM面试

    Jvm内存结构,一般是面试官对Java虚拟机这块考察的第一问. Java虚拟机的内存结构一般可以从线程共有和线程私有两部分起头作答,然后再详细说明各自的部分,类似树状结构的作答,好处就是思路清晰,面试 ...

  3. 深浅拷贝_python

    一.浅拷贝 拷贝第一层的东西,如其他列表修改他们共同的第二层(或更深),他管不了,只能跟着变. 用处:很少用,用不同账号关联共享: import copyhusband= ['chen','123', ...

  4. 使用Samba实现文件共享:Windows和Linux之间

    1.概述: 1987 年,微软公司和英特尔公司共同制定了 SMB(Server Messages Block,服务器消息 块)协议,旨在解决局域网内的文件或打印机等资源的共享问题,这也使得在多个主机之 ...

  5. 使用pdf.js显示pdf文件

    <script type="text/javascript" src="build/pdf.min.js"></script> < ...

  6. 一起了解 .Net Foundation 项目 No.3

    .Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. AutoMapper Au ...

  7. web开发一些资源的在线引用地址

    <!-- Bootstrap --> <link rel="stylesheet" href="https://cdn.bootcss.com/boot ...

  8. springboot10(docker)

    一 Docker 1 what's the Docker? ​ Docker是一个开源的应用容器引擎,轻量级容器技术. ​ Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器 ...

  9. python正则子组匹配

    子组匹配返回找到的第一个匹配项 []表示匹配列表中的任意一个,返回找到的第一个 这样可以发现如果要查找字母的话可以使用[a-z],返回找到的第一个字母 查找数字使用[0-9],返回找到的第一个数字相当 ...

  10. hadoop SecondNamenode详解

    SecondNamenode名字看起来很象是对第二个Namenode,要么与Namenode一样同时对外提供服务,要么相当于Namenode的HA. 真正的了解了SecondNamenode以后,才发 ...