springboot动态cron定时任务

实现动态修改cron表达式来更改定时任务的规则,程序不重启,且使用定时任务线程池加快效率。
一、配置类

@Configuration @EnableAsync @EnableScheduling @Slf4j public class SchedulerThreadPoolConfig implements SchedulingConfigurer, AsyncConfigurer { /** * 定时任务使用的线程池 * @return */ @Bean(destroyMethod = "shutdown", name = "taskScheduler") public ThreadPoolTaskScheduler taskScheduler(){ ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(10); scheduler.setThreadNamePrefix("task-"); scheduler.setAwaitTerminationSeconds(600); scheduler.setWaitForTasksToCompleteOnShutdown(true); return scheduler; }/** * 异步任务执行线程池 * @return */ @Bean(name = "asyncExecutor") public ThreadPoolTaskExecutor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setQueueCapacity(1000); executor.setKeepAliveSeconds(600); executor.setMaxPoolSize(20); executor.setThreadNamePrefix("taskExecutor-"); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.initialize(); return executor; }@Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { ThreadPoolTaskScheduler taskScheduler = taskScheduler(); scheduledTaskRegistrar.setTaskScheduler(taskScheduler); }@Override public Executor getAsyncExecutor() { return asyncExecutor(); }@Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return (throwable, method, objects) -> { log.error("异步任务执行出现异常, message {}, emthod {}, params {}", throwable, method, objects); }; } }

【springboot动态cron定时任务】二、创建一个定时任务接口,继承runnable(就一个任务可不写)
public interface SchedulerTaskJob extends Runnable { }

三、任务实现类
import com.mixislink.entity.Data; import com.mixislink.entity.SubsidyRecord; import com.mixislink.service.DataService; import com.mixislink.service.SubsidyRecordService; import com.mixislink.utils.Constants; import com.mixislink.utils.RedisTool; import com.mixislink.utils.UUIDUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.TriggerContext; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.support.CronTrigger; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * @Author WuSong * @Date 2020-07-10 * @Time 17:17:14 */ @Slf4j @Component public class SettleAccountsTask implements SchedulerTaskJob { @Autowired private RedisTool redisTool; @Resource(name = "taskScheduler") private ThreadPoolTaskScheduler threadPoolTaskScheduler; @Override public void run() { //do something log.info("定时任务执行完毕!"); }//启动或更新定时任务 public void doStartTask(){ //redis中取表达式 String taskCron=redisTool.get(Constants.RULES_KEY); if (StringUtils.isNotBlank(taskCron)){ Trigger trigger = new Trigger() { @Override public Date nextExecutionTime(TriggerContext triggerContext) { CronTrigger cronTrigger = new CronTrigger(taskCron); return cronTrigger.nextExecutionTime(triggerContext); } }; threadPoolTaskScheduler.schedule(this, trigger); } }}

四、加入启动时读cron表达式
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * @Author WuSong * @Date 2020-07-13 * @Time 16:55:13 */ @Component @Order(1) public class TaskTriggerRunner implements CommandLineRunner { @Autowired private SettleAccountsTask settleAccountsTask; @Override public void run(String... args) throws Exception { settleAccountsTask.doStartTask(); } }

五、提供web接口方式修改cron表达式
@PutMapping public HttpEntity updateRules(@RequestBody Rules rules){ try { String[] time = rules.getTime().split(":"); int date = rules.getDate(); String cron = null; if (rules.getType() == 1){ //0 0 6 ? * 1每周一6点 cron = new StringBuffer(time[2]).append(" ").append(time[1]).append(" ") .append(time[0]).append(" ").append("?").append(" ").append("*") .append(" ").append(date).toString(); }else if (rules.getType() == 2){ //0 0 6 20 * ?每月20号6点 cron = new StringBuffer(time[2]).append(" ").append(time[1]).append(" ") .append(time[0]).append(" ").append(date).append(" ").append("*") .append(" ").append("?").toString(); }else if (rules.getType() == 3){ //0 0 6 20 2 ?每年2月20号6点 cron = new StringBuffer(time[2]).append(" ").append(time[1]).append(" ") .append(time[0]).append(" ").append(date).append(" ").append(rules.getMonth()) .append(" ").append("?").toString(); } //将cron表达式放入redis if (cron!=null) redisTool.set(Constants.RULES_KEY, cron); //更新一下定时任务的表达式 settleAccountsTask.doStartTask(); return new HttpEntity(); } catch (Exception e) { log.error("settleAccounts",e); return new HttpEntity(Define.STATUS_INTERNAL_ERROR,Define.MSG_INTERNAL_ERROR); } }//Rules类字段,封装给前端用的 private Integer type; //1每周 2 每月 3 每年 private Integer date; //周1234567 月1-31 年1-12 private String time; //时分秒 private Integer month; //月份(每年专用)


    推荐阅读