本文主要是介绍springboot使用Scheduling实现动态增删启停定时任务教程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《springboot使用Scheduling实现动态增删启停定时任务教程》:本文主要介绍springboot使用Scheduling实现动态增删启停定时任务教程,具有很好的参考价值,希望对大家有...
在项目开发过程中,如果是一些简单的工程,非分布式工程,一般我们可以使用@EnableScheduling注解和@Scheduled注解实现简单的定时任务,也可以使用SchedulingConfigurer接口来实现定时任务。那如何动态的来生成定时任务呢?
下面是具体步骤,可以结合数据库,来存储定时任务所需要的参数数据,如bean的名称、方法名,方法参数、执行的表达式等等。
1、配置定时任务需要的线程池
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; // 配置定时任务线程池 @Configuration public class SchedulingConfig { @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); // 定时任务执行线程池核心线程数 taskScheduler.setPoolSize(4); taskScheduler.setRemoveOnCancelPolicy(true); taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-test-"); return taskScheduler; } }
2、创建ScheduledFuture的包装类
// ScheduledFuture的包装类 public final class ScheduledTask { volatile ScheduledFuture<?> future; /** * 取消定时任务 */ public void cancel() { ScheduledFuture<?> future = this.future; if (future != null) { future.cancel(true); } } }
3、注册定时任务,增加、删除任务
/** * 添加定时任务注册,用来增加、删除定时任务。 */ @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; } // 添加定时任务 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)); } } // 移除定时任务 public void removeCronTask(Runnable task) { ScheduledTask scheduledTask = this.scheduledTasks.remove(task); if (scheduledTask != null) scheduledTask.cancel(China编程); } 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(); } }
4、创建具体执行bean中方法的类
// 添加Runnable接口实现类,被定时任务线程池调用,用来执行指定bean里面的方法。 @Slf4j public class SchedulingRunnable implements Runnable { // bean名称 private String beanName; // 方法名称 private String methodName; // 方法参数 private String params; public SchedulingRunnable(String beanName, String methodName) { this(beanName, methodName, null); } public SchedulingRunnable(String beanName, String methodName, String params) { this.beanName = beanName; this.methodName = methodName; this.params = params; } @Override public void run() { log.info("定时任务开始执行 - bean:{},方法:{},参数:{}", beanName, methodName, params); long startTime = System.currentTimeMillis(); try { Object target = SpringContextUtils.getBean(beanNapythonme); Method method = null; if (StringUtils.isNotEmpty(params)) { method = target.getClass().getDeclaredMethod(methodName, String.class); } else { method = target.getClass().getDeclaredMethod(methodName); } ReflectionUtils.makeAccessible(method); if (StringUtils.isNotEmpty(params)) { method.invoke(target, params); } else { method.invoke(target); } } catch (Exception ex) { log.error(String.format("定时任务执行异常 - bean:%s,方法:%s,参数:%s ", beanName, methodName, params), ex); } long times = System.currentTimeMillis() - startTime; log.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); } }
5、从spring容器里获取bean
// 从spring容器里获取bean @Component public class SpringContextUtils implements ApplicationContextAware { private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { SpringContextUtils.applicationContext = applicationContext; } public static Object getBean(String name) { return applicationContext.getBean(name); } public static <T> T getBean(Class<T> requiredType) { return applicationContext.getBean(requiredType); } public static <T> T getBean(String name, Class<T> requiredType) { return applicationContext.getBean(name, requiredType); } public static boolean containsBean(String name) { return applicationContext.containsBean(name); } public static boolean isSingleton(String name) { return applicationContext.isSingleton(name); } public static Class<? extends Object> getType(String name) { return applicationContext.getType(name); } }
6、创建具体执行的bean以及方法
// 测试类 @Component("testTask") public class TestTask { /** * 有参方法 * @param params */ public void taskWithParams(String params) { System.out.println("执行有参示例任务:" + params); } /** * 无惨方法 */ public void taskNoParams() { System.out.println("执行无参示例任务"); } }
7、接口测试类
@RestController @RequestMapping("/test") public class TestController { @Autowired private CronTaskRegistrar cronTaskRegistrar; @RequestMapping("/addTest") public String addTest(boolean flg){ SchedulingRunnable task; if (flg) { // 创建无惨任务 task = new SchedulingRunnable("testTask", "taskNoParams"); } else { task = new SchedulingRunnable("testTask", "taskWithParams", "hello word"); } cronTaskRegistrar.addCronTask(task, "0/1 * * * * *"); return "ok"; } @RequestMapping("/updateTest") public String updateTest(boolean flg){ //先移除再添加 if(flg) { // 创建无惨任务 SchedulingRunnable task = new SchedulingRunnable("testTask", "taskNoParams"); cronTaskRegistrar.removeCronTask(task); } else { SchedulingRunnable task = new SchedulingRunnable("testTask", "taskWithParams", "hello word"); cronTaskRegistrar.removeCronTask(task); } SchedulingRunnable task = new SchedulingRunnable("testTask", "taskWithParams", "hello word"); cronTaskRegistrar.addCronTask(task, "0/5 * * * * *"); return "ok"; } @RequestMapping("/delTest") public String delTest(){ SchedulingRunnable task = new SchedulingRunnable("testTask", "taskNoParams"); js cronTaskRegistrar.removeCronTask(task); return "ok"; } @RequestMapping("/startTest") public String startTest(boolean flg){ /** * 启停定时任务的逻辑就是创建新的任务或者删除任务,参数一致即可 * 可以结合数据库,将配置信息存入数据库 */ if(flg) { SchedulingRunnable task = new SchedulingRunnable("testTask", "taskNoParams"); cronTaskRegistrar.addCronTask(task, "0/5 * * * * *"); } else { SchedulingRunnable task = new SchedulingRunnaphpbmPfpXle("testTask", "taskNoParams"); cronTaskRegistrar.removeCronTask(task); } return "ok"; } }
8、结合数据库,创建对应的实体
// 定时任务实体 @Data public class JobEntity { /** * 任务ID */ private Integer jobId; /** * bean名称 */ private String beanName; /** * 方法名称 */ private String methodName; /** * 方法参数 */ private String methodParams; /** * cron表达式 */ private String cronExpression; /** * 状态(1正常 0暂停) */ private Integer jobStatus; /** * 备注 */ private String remark; /** * 创建时间 */ private Date createTime; /** * 更新时间 */ private Date updateTime; }
9、读取数据库要执行的任务
在程序启动的时候,读取数据库,并创建要执行任务
/** * @description: 初始化数据库任务,可以再程启动的时候加载数据库里的任务 * @author: HK * @since: 2025/4/21 18:21 */ @Component @Slf4j public class InitTask implements CommandLineRunner { @Autowired private CronTaskRegistrar cronTaskRegistrar; @Override public void run(String... args) { // 初始加载数据库里状态为正常的定时任务 /* List<SysJobPO> jobList = service.getJobList("1"); if (CollectionUtils.isNotEmpty(jobList)) { for (SysJobPO job : jobList) { SchedulingRunnable task = new SchedulingRunnable(job.getBeanName(), job.getMethodName(), job.getMethodParams()); cronTaskRegistrar.addCronTask(task, job.getCronExpression()); } log.info("定时任务已加载完毕..."); }*/ } }
总结
这篇关于springboot使用Scheduling实现动态增删启停定时任务教程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!