SpringBoot实现动态控制定时任务支持多参数功能

由于工作上的原因,需要进行定时任务的动态增删改查,网上大部分资料都是整合quertz框架实现的。本人查阅了一些资料,发现springBoot本身就支持实现定时任务的动态控制。并进行改进,现支持任意多参数定时任务配置

实现结果如下图所示:

后台测试显示如下:

github 简单demo地址如下:

springboot-dynamic-task

1.定时任务的配置类:SchedulingConfig

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
/**
 * @program: simple-demo
 * @description: 定时任务配置类
 * @author: CaoTing
 * @date: 2019/5/23
 **/
@Configuration
public class SchedulingConfig {
  @Bean
  public TaskScheduler taskScheduler() {
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    // 定时任务执行线程池核心线程数
    taskScheduler.setPoolSize(4);
    taskScheduler.setRemoveOnCancelPolicy(true);
    taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
    return taskScheduler;
  }
}

2.定时任务注册类:CronTaskRegistrar

这个类包含了新增定时任务,移除定时任务等等核心功能方法

import com.caotinging.demo.task.ScheduledTask;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * @program: simple-demo
 * @description: 添加定时任务注册类,用来增加、删除定时任务。
 * @author: CaoTing
 * @date: 2019/5/23
 **/
@Component
public class CronTaskRegistrar implements DisposableBean {
  private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);
  @Autowired
  private TaskScheduler taskScheduler;
  public TaskScheduler getScheduler() {
    return this.taskScheduler;
  }
  /**
   * 新增定时任务
   * @param task
   * @param cronExpression
   */
  public void addCronTask(Runnable task, String cronExpression) {
    addCronTask(new CronTask(task, cronExpression));
  }
  public void addCronTask(CronTask cronTask) {
    if (cronTask != null) {
      Runnable task = cronTask.getRunnable();
      if (this.scheduledTasks.containsKey(task)) {
        removeCronTask(task);
      }
      this.scheduledTasks.put(task, scheduleCronTask(cronTask));
    }
  }
  /**
   * 移除定时任务
   * @param task
   */
  public void removeCronTask(Runnable task) {
    ScheduledTask scheduledTask = this.scheduledTasks.remove(task);
    if (scheduledTask != null)
      scheduledTask.cancel();
  }
  public ScheduledTask scheduleCronTask(CronTask cronTask) {
    ScheduledTask scheduledTask = new ScheduledTask();
    scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
    return scheduledTask;
  }
  @Override
  public void destroy() {
    for (ScheduledTask task : this.scheduledTasks.values()) {
      task.cancel();
    }
    this.scheduledTasks.clear();
  }
}

3.定时任务执行类:SchedulingRunnable

import com.caotinging.demo.utils.SpringContextUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.Objects;
/**
 * @program: simple-demo
 * @description: 定时任务运行类
 * @author: CaoTing
 * @date: 2019/5/23
 **/
public class SchedulingRunnable implements Runnable {
  private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);
  private String beanName;
  private String methodName;
  private Object[] params;
  public SchedulingRunnable(String beanName, String methodName) {
    this(beanName, methodName, null);
  }
  public SchedulingRunnable(String beanName, String methodName, Object...params ) {
    this.beanName = beanName;
    this.methodName = methodName;
    this.params = params;
  }
  @Override
  public void run() {
    logger.info("定时任务开始执行 - bean:{},方法:{},参数:{}", beanName, methodName, params);
    long startTime = System.currentTimeMillis();
    try {
      Object target = SpringContextUtils.getBean(beanName);
      Method method = null;
      if (null != params && params.length > 0) {
        Class<?>[] paramCls = new Class[params.length];
        for (int i = 0; i < params.length; i++) {
          paramCls[i] = params[i].getClass();
        }
        method = target.getClass().getDeclaredMethod(methodName, paramCls);
      } else {
        method = target.getClass().getDeclaredMethod(methodName);
      }
      ReflectionUtils.makeAccessible(method);
      if (null != params && params.length > 0) {
        method.invoke(target, params);
      } else {
        method.invoke(target);
      }
    } catch (Exception ex) {
      logger.error(String.format("定时任务执行异常 - bean:%s,方法:%s,参数:%s ", beanName, methodName, params), ex);
    }
    long times = System.currentTimeMillis() - startTime;
    logger.info("定时任务执行结束 - bean:{},方法:{},参数:{},耗时:{} 毫秒", beanName, methodName, params, times);
  }
  @Override
  public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    SchedulingRunnable that = (SchedulingRunnable) o;
    if (params == null) {
      return beanName.equals(that.beanName) &&
          methodName.equals(that.methodName) &&
          that.params == null;
    }
    return beanName.equals(that.beanName) &&
        methodName.equals(that.methodName) &&
        params.equals(that.params);
  }
  @Override
  public int hashCode() {
    if (params == null) {
      return Objects.hash(beanName, methodName);
    }
    return Objects.hash(beanName, methodName, params);
  }
}

4.定时任务控制类:ScheduledTask

import java.util.concurrent.ScheduledFuture;
/**
 * @program: simple-demo
 * @description: 定时任务控制类
 * @author: CaoTing
 * @date: 2019/5/23
 **/
public final class ScheduledTask {
  public volatile ScheduledFuture<?> future;
  /**
   * 取消定时任务
   */
  public void cancel() {
    ScheduledFuture<?> future = this.future;
    if (future != null) {
      future.cancel(true);
    }
  }
}

5.定时任务的测试

编写一个需要用于测试的任务类

import org.springframework.stereotype.Component;
/**
 * @program: simple-demo
 * @description:
 * @author: CaoTing
 * @date: 2019/5/23
 **/
@Component("demoTask")
public class DemoTask {
  public void taskWithParams(String param1, Integer param2) {
    System.out.println("这是有参示例任务:" + param1 + param2);
  }
  public void taskNoParams() {
    System.out.println("这是无参示例任务");
  }
}

进行单元测试

import com.caotinging.demo.application.DynamicTaskApplication;
import com.caotinging.demo.application.SchedulingRunnable;
import com.caotinging.demo.config.CronTaskRegistrar;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
 * @program: simple-demo
 * @description: 测试定时任务
 * @author: CaoTing
 * @date: 2019/5/23
 **/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = DynamicTaskApplication.class)
public class TaskTest {
  @Autowired
  CronTaskRegistrar cronTaskRegistrar;
  @Test
  public void testTask() throws InterruptedException {
    SchedulingRunnable task = new SchedulingRunnable("demoTask", "taskNoParams", null);
    cronTaskRegistrar.addCronTask(task, "0/10 * * * * ?");
    // 便于观察
    Thread.sleep(3000000);
  }
  @Test
  public void testHaveParamsTask() throws InterruptedException {
    SchedulingRunnable task = new SchedulingRunnable("demoTask", "taskWithParams", "haha", 23);
    cronTaskRegistrar.addCronTask(task, "0/10 * * * * ?");
    // 便于观察
    Thread.sleep(3000000);
  }
}

6.工具类:SpringContextUtils

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
 * @program: simple-demo
 * @description: spring获取bean工具类
 * @author: CaoTing
 * @date: 2019/5/23
 **/
@Component
public class SpringContextUtils implements ApplicationContextAware {
  private static ApplicationContext applicationContext = null;
  @Override
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    if (SpringContextUtils.applicationContext == null) {
      SpringContextUtils.applicationContext = applicationContext;
    }
  }
  //获取applicationContext
  public static ApplicationContext getApplicationContext() {
    return applicationContext;
  }
  //通过name获取 Bean.
  public static Object getBean(String name) {
    return getApplicationContext().getBean(name);
  }
  //通过class获取Bean.
  public static <T> T getBean(Class<T> clazz) {
    return getApplicationContext().getBean(clazz);
  }
  //通过name,以及Clazz返回指定的Bean
  public static <T> T getBean(String name, Class<T> clazz) {
    return getApplicationContext().getBean(name, clazz);
  }
}

7.我的pom依赖

<dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatisplus-spring-boot-starter</artifactId>
      <version>1.0.5</version>
    </dependency>
    <dependency>
      <groupId>com.baomidou</groupId>
      <artifactId>mybatis-plus</artifactId>
      <version>2.1.9</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid-spring-boot-starter</artifactId>
      <version>1.1.9</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 数据库-->
    <!--<dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
    </dependency>-->
    <!-- https://mvnrepository.com/artifact/com.hynnet/oracle-driver-ojdbc -->
    <!--<dependency>
      <groupId>com.oracle</groupId>
      <artifactId>ojdbc6</artifactId>
      <version>11.2.0.1.0</version>
    </dependency>-->
    <!-- 单元测试 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>provided</scope>
    </dependency>
    <!--redisTemplate -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>2.7.3</version>
    </dependency>
    <!-- http连接 restTemplate -->
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient-cache</artifactId>
    </dependency>
    <!-- 工具-->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.31</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
    </dependency>
    <dependency>
      <groupId>commons-lang</groupId>
      <artifactId>commons-lang</artifactId>
      <version>2.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.google/guava -->
    <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>10.0.1</version>
    </dependency>
    <!-- pinyin4j -->
    <dependency>
      <groupId>com.belerweb</groupId>
      <artifactId>pinyin4j</artifactId>
      <version>2.5.0</version>
    </dependency>
  </dependencies>

8.总结

建议移步github获取简单demo上手实践哦,在本文文首哦。有帮助的话点个赞吧,笔芯。

以上所述是小编给大家介绍的SpringBoot实现动态控制定时任务支持多参数功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • springboot整合Quartz实现动态配置定时任务的方法

    前言 在我们日常的开发中,很多时候,定时任务都不是写死的,而是写到数据库中,从而实现定时任务的动态配置,下面就通过一个简单的示例,来实现这个功能. 一.新建一个springboot工程,并添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency

  • 详解SpringBoot定时任务说明

    1. 定时任务实现方式 定时任务实现方式: Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务.使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行.一般用的较少,这篇文章将不做详细介绍. 使用Quartz,这是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,配置起来稍显复杂,有空介绍. SpringBoot自带的Scheduled,可以将它看成一个轻量级的Quartz,而且使用起来比Q

  • springboot集成schedule实现定时任务

    背景 在项目开发过程中,我们经常需要执行具有周期性的任务.通过定时任务可以很好的帮助我们实现. 我们拿常用的几种定时任务框架做一个比较: 从以上表格可以看出,Spring Schedule框架功能完善,简单易用.对于中小型项目需求,Spring Schedule是完全可以胜任的. 1.springboot集成schedule 1.1 添加maven依赖包 由于Spring Schedule包含在spring-boot-starter基础模块中了,所有不需要增加额外的依赖. <dependenci

  • spring boot整合quartz实现多个定时任务的方法

    最近收到了很多封邮件,都是想知道spring boot整合quartz如何实现多个定时任务的,由于本人生产上并没有使用到多个定时任务,这里给个实现的思路. 1.新建两个定时任务,如下: public class ScheduledJob implements Job{ @Override public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("sched

  • 详解Spring Boot中使用@Scheduled创建定时任务

    我们在编写Spring Boot应用中经常会遇到这样的场景,比如:我需要定时地发送一些短信.邮件之类的操作,也可能会定时地检查和监控一些标志.参数等. 创建定时任务 在Spring Boot中编写定时任务是非常简单的事,下面通过实例介绍如何在Spring Boot中创建定时任务,实现每过5秒输出一下当前时间. 在Spring Boot的主类中加入@EnableScheduling注解,启用定时任务的配置 @SpringBootApplication @EnableScheduling publi

  • SpringBoot 定时任务遇到的坑

    前言 springboot已经支持了定时任务Schedule模块,一般情况已经完全能够满足我们的实际需求.今天就记录一下我使用 schedule 时候踩的坑吧. 想要使用定时,我们首先要开启支持,其实就是在启动类上面加个注解就 Ok. @SpringBootApplication @EnableScheduling public class Application { public static void main(String[] args) { SpringApplication.run(A

  • spring-boot通过@Scheduled配置定时任务及定时任务@Scheduled注解的方法

    串行的定时任务 @Component public class ScheduledTimer { private Logger logger = Logger.getLogger(this.getClass()); /** * 定时任务,1分钟执行1次,更新潜在客户超时客户共享状态 */ @Scheduled(cron="0 0/1 8-20 * * ?") public void executeUpdateCuTask() { Thread current = Thread.curr

  • SpringBoot定时任务两种(Spring Schedule 与 Quartz 整合 )实现方法

    前言 最近在项目中使用到定时任务,之前一直都是使用Quartz 来实现,最近看Spring 基础发现其实Spring 提供 Spring Schedule 可以帮助我们实现简单的定时任务功能. 下面说一下两种方式在Spring Boot 项目中的使用. Spring Schedule 实现定时任务 Spring Schedule 实现定时任务有两种方式 1. 使用XML配置定时任务, 2. 使用 @Scheduled 注解. 因为是Spring Boot 项目 可能尽量避免使用XML配置的形式,

  • 详解SpringBoot 创建定时任务(配合数据库动态执行)

    序言:创建定时任务非常简单,主要有两种创建方式:一.基于注解(@Scheduled) 二.基于接口(SchedulingConfigurer). 前者相信大家都很熟悉,但是实际使用中我们往往想从数据库中读取指定时间来动态执行定时任务,这时候基于接口的定时任务就大派用场了. 一.静态定时任务(基于注解) 基于注解来创建定时任务非常简单,只需几行代码便可完成. @Scheduled 除了支持灵活的参数表达式cron之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应

  • SpringBoot实现动态控制定时任务支持多参数功能

    由于工作上的原因,需要进行定时任务的动态增删改查,网上大部分资料都是整合quertz框架实现的.本人查阅了一些资料,发现springBoot本身就支持实现定时任务的动态控制.并进行改进,现支持任意多参数定时任务配置 实现结果如下图所示: 后台测试显示如下: github 简单demo地址如下: springboot-dynamic-task 1.定时任务的配置类:SchedulingConfig import org.springframework.context.annotation.Bean

  • Springboot自带定时任务实现动态配置Cron参数方式

    目录 Springboot自带定时任务实现动态配置Cron参数 SpringBoot定时任务的四种实现方式(主要) spring动态配置cron表达式,不需要停服 SchedulingConfigurer接口实现动态加载cron表达式 Springboot自带定时任务实现动态配置Cron参数 同学们,我今天分享一下SpringBoot动态配置Cron参数.场景是这样子的:后台管理界面对定时任务进行管理,可动态修改执行时间,然后保存入库,每次任务执行前从库里查询时间,以达到动态修改Cron参数的效

  • Springboot一个注解搞定返回参数key转换功能

    目录 前言 正文 前言 平时在搬砖的时候,大家有没有遇到过这样的一个场景,由于各种不可描述因素导致, 一个接口返回的数据 里面的 key 是 A , 但是客户端(前端) 要求返回的key 不叫 A 叫 Aa . 也就是返回的值不变,就是key 换了. 例如 : 正文 那么需要怎么做的 ? ① 新写一个类,用于值的返回,拿到值,把属性 get set 一下. ② 也就是本篇文章想提到的 ,使用注解, @JsonProperty 这个很多人都知道, 绕半天原来是 炒冷饭 ? 且慢. ② 这种方式,其

  • SpringBoot实现quartz定时任务可视化管理功能

    前言 在实际框架或产品开发过程中,springboot中集成quarzt方式基本是以job和trigger的bean对象方式直接硬编码完成的,例如以下代码示例.对于系统内定义的所有定时任务类型,具体执行类,执行策略,运行状态都没有一个动态全局的管理,所有决定将quartz做成可视化配置管理,便于统一管理,也降低了使用门槛,只需要关心job类的实现即可 @Bean public JobDetail SMSJobDetail() { return JobBuilder.newJob(SMSJob.c

  • jQuery实现浏览器之间跳转并传递参数功能【支持中文字符】

    本文实例讲述了jQuery实现浏览器之间跳转并传递参数功能.分享给大家供大家参考,具体如下: one.html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <script src="https://cdn.bootcss.com/jquery/2.2.2/jquery.slim.js">&l

  • 浅谈springboot项目中定时任务如何优雅退出

    在一个springboot项目中需要跑定时任务处理批数据时,突然有个Kill命令或者一个Ctrl+C的命令,此时我们需要当批数据处理完毕后才允许定时任务关闭,也就是当定时任务结束时才允许Kill命令生效. 启动类 启动类上我们获取到相应的上下文,捕捉相应命令.在这里插入代码片 @SpringBootApplication /**指定mapper对应包的路径*/ @MapperScan("com.youlanw.kz.dao") /**开启计划任务*/ @EnableScheduling

  • springboot如何配置定时任务

    概述 在Java环境下创建定时任务有多种方式: 使用while循环配合 Thread.sleep(),虽然稍嫌粗陋但也勉强可用 使用 Timer和 TimerTask 使用 ScheduledExecutorService 定时任务框架,如Quartz 在SpringBoot下执行定时任务无非也就这几种方式(主要还是后两种).只不过SpringBoot做了许多底层的工作,我们只需要做些简单的配置就行了. 通过注解实现定时任务 在SpringBoot中仅通过注解就可以实现常用的定时任务.步骤就两步

  • Springboot实现动态定时任务流程详解

    目录 一.静态 二.动态 1.基本代码 2.方案详解 2.1 初始化 2.2 单次执行 2.3 停止任务 2.4 启用任务 三.小结 一.静态 静态的定时任务可以直接使用注解@Scheduled,并在启动类上配置@EnableScheduling即可 @PostMapping("/list/test1") @Async @Scheduled(cron = "0 * * * * ?") public void test1() throws Exception { Ob

  • SpringBoot Mybatis Plus公共字段自动填充功能

    一.应用场景 平时在建对象表的时候都会有最后修改时间,最后修改人这两个字段,对于这些大部分表都有的字段,每次在新增和修改的时候都要考虑到这几个字段有没有传进去,很麻烦.mybatisPlus有一个很好的解决方案.也就是公共字段自动填充的功能.一般满足下面条件的字段就可以使用此功能: 这个字段是大部分表都会有的. 这个字段的值是固定的,或则字段值是可以在后台动态获取的. 常用的就是last_update_time,last_update_name这两个字段. 二.配置MybatisPlus 导包:

  • springboot实现添加邮件发送及压缩功能

    这次本来只讲讲邮件发送功能的,惮于内容比较贫乏,故加了点儿文件压缩的功能讲解. 首先邮件发送,邮件功能在springboot里面是有对应的依赖组件,这个: <dependency> <groupId>org.springframework.boot</groupId> <artifactId> spring-boot-starter-mail</artifactId> </dependency> 邮件功能开发在springboot里面

随机推荐