现在的位置: 首页 > 编程语言 > 正文

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

2020年02月14日 编程语言 ⁄ 共 10277字 ⁄ 字号 评论关闭

由于工作上的原因,需要进行定时任务的动态增删改查,网上大部分资料都是整合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 **/@Configurationpublic 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 **/@Componentpublic 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 **/@Componentpublic 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实现动态控制定时任务支持多参数功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

本文标题: SpringBoot实现动态控制定时任务支持多参数功能

以上就上有关SpringBoot实现动态控制定时任务支持多参数功能的相关介绍,要了解更多spring,boot,定时任务,spring,boot动态定时任务内容请登录学步园。

抱歉!评论已关闭.