欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2024-02-21 21:35:22
由于工作上的原因,需要进行定时任务的动态增删改查,网上大部分资料都是整合quertz框架实现的。本人查阅了一些资料,发现springboot本身就支持实现定时任务的动态控制...

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

实现结果如下图所示:

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

后台测试显示如下:

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实现动态控制定时任务支持多参数功能,希望对大家有所帮助

上一篇: 学习非阻塞的同步机制CAS

下一篇: