SpringBoot实现动态控制定时任务支持多参数功能
程序员文章站
2024-02-21 21:35:22
由于工作上的原因,需要进行定时任务的动态增删改查,网上大部分资料都是整合quertz框架实现的。本人查阅了一些资料,发现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实现动态控制定时任务支持多参数功能,希望对大家有所帮助
上一篇: 学习非阻塞的同步机制CAS