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);
        };
    }
}

二、创建一个定时任务接口,继承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;//月份(每年专用)

 

你可能感兴趣的:(java)