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

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

@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. 未能加载文件或程序集“Autofac.Integration.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=17863af14b0044da”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。 (异常来自 HRESULT:0x80131040)

    是因为web.config中dependentAssembly结点下的版本号和当前引用的程序集的版本号不一致!

  2. scw——01 java.lang.IllegalStateException: Could not initialize plugin: interface org.mockito.plugins.MockMake

    错误: java.lang.IllegalStateException: Could not initialize plugin: interface org.mockito.plugins.Mock ...

  3. 为什么需要激活函数 为什么需要归一化 python内置函数:enumerate用法总结

    为什么需要激活函数 为什么需要归一化 python内置函数:enumerate用法总结 待办 激活函数的用途(为什么需要激活函数)? 如果不用激励函数(其实相当于激励函数是f(x) = x),在这种情 ...

  4. 寒假安卓app开发学习记录(7)

    今天学习了Intent的基本用法.Intent是什么?Intent在Android中的核心作用就是“跳转”(Android中的跳转机制),同时可以携带必要的信息,将Intent作为一个信息桥梁.最常用 ...

  5. Python多线程join/setDaemon

    import threading, time class Test(): def test1(self): print("--") time.sleep(3) print(&quo ...

  6. drc实现

    原理参考之前转载的matlab上关于DRC的描述. 目前主要实现了compressor和expander. compressor: Limit: expander: 实现代码: #include< ...

  7. [Note]后缀数组

    后缀数组 代码 void rsort() { for (int i = 1; i <= m; ++i) tax[i] = 0; for (int i = 1; i <= n; ++i) + ...

  8. CI框架发送邮件(带附件)

    最近写了一个发送带附件的邮件,发邮件挺简单的,在我这里最重要的是遇到问题,哈哈哈哈 1.主要方法看代码 public function send_mail(){ $this->load-> ...

  9. Added non-passive event listener to a scroll-blocking 'touchmove' event. Consider marking event handler as 'passive' to make the page more responsive

     Vue控制台警告:  Added non-passive event listener to a scroll-blocking 'touchmove' event. Consider markin ...

  10. mybatis--Spring整合mybatis

    今天学习了mybatis整合Spring开发,做了一个mybatis+spring的小实例 (1)首先,创建数据库my,并在数据库my中创建表user create database my; use ...