欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot創(chuàng)建動態(tài)定時任務的幾種方式小結(jié)

 更新時間:2024年10月20日 11:14:26   作者:藍眸少年CY  
SpringBoot提供了多種實現(xiàn)定時任務的方式,包括使用@Scheduled注解、SchedulingConfigurer接口、TaskScheduler接口和Quartz框架,@Scheduled適合簡單的定時任務,文中通過代碼示例介紹的非常詳細,需要的朋友可以參考下

一、使用 @Scheduled 注解

@Scheduled 是 Spring 提供的一個注解,用于標記需要定時執(zhí)行的方法。常見的屬性包括:

  • cron :通過 Cron 表達式定義任務的執(zhí)行時間。
  • fixedRate :定義任務的固定執(zhí)行頻率,以毫秒為單位。
  • fixedDelay :定義任務在前一次執(zhí)行完畢后延遲多少毫秒再執(zhí)行。

代碼示例:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
@Component
public class ScheduledTasks {
 
    @Scheduled(cron = "0 0 * * * ?") // 每小時整點執(zhí)行一次
    public void reportCurrentTime() {
        System.out.println("現(xiàn)在時間:" + System.currentTimeMillis());
    }
 
    @Scheduled(fixedRate = 5000) // 每5秒執(zhí)行一次
    public void fixedRateTask() {
        System.out.println("每5秒執(zhí)行一次任務:" + System.currentTimeMillis());
    }
 
    @Scheduled(fixedDelay = 7000) // 前一次執(zhí)行完畢后延遲7秒執(zhí)行
    public void fixedDelayTask() {
        System.out.println("延遲7秒后執(zhí)行任務:" + System.currentTimeMillis());
    }
}

@Scheduled 適用于大多數(shù)簡單的定時任務場景,如定時發(fā)送郵件或生成報告等。然而,它的靈活性較差,對于復雜的任務調(diào)度需求,或需要動態(tài)調(diào)整任務時間的場景,可能并不適用。

二、使用 SchedulingConfigurer 接口

SchedulingConfigurer 接口允許我們通過編程方式配置任務調(diào)度器(TaskScheduler)。通過實現(xiàn)這個接口,我們可以靈活地設(shè)置任務的調(diào)度規(guī)則,甚至動態(tài)地添加或移除任務。

簡單使用代碼:

public class TaskConfig implements SchedulingConfigurer {
    
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(
                //1.添加任務內(nèi)容(Runnable)
                () -> System.out.println("執(zhí)行定時任務2: " + LocalDateTime.now().toLocalTime()),
                //2.設(shè)置執(zhí)行周期(Trigger)
                triggerContext -> {
                    //2.1 從數(shù)據(jù)庫獲取執(zhí)行周期
                    String cron = zhyMapper.getCron();
                    //2.2 合法性校驗.
                    if (StringUtils.isEmpty(cron)) {
                        // Omitted Code ..
                    }
                    //2.3 返回執(zhí)行周期(Date)
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                }
        );
 
    }
}

詳細增刪該查操作:

  • 動態(tài)注冊bean
public class ApplicationContextUtils implements ApplicationContextAware {
 
    private static ApplicationContext CONTEXT;
    /**
     * 設(shè)置spring上下文
     * @param ctx spring上下文
     * @throws BeansException
     * */
    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        CONTEXT = ctx;
    }
 
    /**
     * 獲取容器
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        return CONTEXT;
    }
 
    /**
     * 獲取容器對象
     * @param type
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> type) {
        return CONTEXT.getBean(type);
    }
 
    public static <T> T getBean(String name,Class<T> clazz){
        return CONTEXT.getBean(name, clazz);
    }
 
    public static Object getBean(String name){
        return CONTEXT.getBean(name);
    }
 
    /**
     * springboot動態(tài)注冊bean
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T register(Class<T> clazz) {
		ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) ApplicationContextUtils.getApplicationContext();
		DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableApplicationContext.getBeanFactory();
		BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
        if(defaultListableBeanFactory.getBeanNamesForType(clazz).length > 0) {
            return defaultListableBeanFactory.getBean(clazz);
        }
		defaultListableBeanFactory.registerBeanDefinition(clazz.getName(), beanDefinitionBuilder.getRawBeanDefinition());
		return (T) ApplicationContextUtils.getBean(clazz.getName());
    }
}
 
  • 任務實體
public class Job {
 
    /**
     * 任務id, 用于標識,默認使用全限定類名
     */
    private String jobId;
 
    /**
     * 任務名稱, 默認簡單類名
     */
    private String jobName;
 
    /**
     * cron表達式, 修改后即可生效
     */
    private String cron;
 
    /**
     * 任務描述
     */
    private String description;
 
    /**
     * 是否啟用, 默認啟用, 修改后即可生效
     */
    private boolean enable = true;
 
    /**
     * 是否處于等待執(zhí)行下個任務的狀態(tài)
     */
    private boolean active;
    /**
     * 任務運行類
     */
    private Class<? extends Runnable> clazz;
}
  • 操作類
public class JobHandler {
 
    private ScheduledTask scheduledTask;
 
    private TriggerTask triggerTask;
 
    private TriggerContext triggerContext;
}
  • 配置SchedulingConfigurer
public class JobSchedulingConfigurer implements SchedulingConfigurer {
 
    private ScheduledTaskRegistrar registrar;
 
    /**
     * 線程池任務調(diào)度器
     */
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(Runtime.getRuntime().availableProcessors() / 3 + 1);
        scheduler.setThreadNamePrefix("TaskScheduler-");
        scheduler.setRemoveOnCancelPolicy(true);  // 保證能立刻丟棄運行中的任務
 
        taskScheduler = scheduler; // 獲取 句柄,方便后期獲取 future
 
        return scheduler;
    }
 
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setTaskScheduler(taskScheduler());
        this.registrar = scheduledTaskRegistrar;
    }
 
    public ScheduledTaskRegistrar getRegistrar() {
        return registrar;
    }
 
    public void setRegistrar(ScheduledTaskRegistrar registrar) {
        this.registrar = registrar;
    }
}
  • 增刪改查
public class SchedulerManager {
 
    /**
     * 任務容器
     */
    private Map<Job, JobHandler> tasks = new ConcurrentHashMap<>();
 
    /**
     * 任務注冊
     */
    @Autowired
    private JobSchedulingConfigurer register;
 
    /**
     * 新增任務, 自生效
     * @param job 任務實體
     * @return 返回新增的任務
     */
    public Job addJob(Job job) {
        Assert.notNull(job, "job can't be null");
        ScheduledTaskRegistrar registrar = register.getRegistrar();
        Runnable runnable = ApplicationContextUtils.register(job.getClazz());
        if(job.getJobId() == null || "".equals(job.getJobId())) {
            job.setJobId(job.getClazz().getName());
        }
        Assert.isNull(this.getJob(job.getJobId()), "任務[" + job.getJobId() + "]已存在");
        if(job.getJobName() == null || "".equals(job.getJobName())) {
            job.setJobName(ClassUtils.getShortName(job.getClazz()));
        }
        CronExpress cron = AnnotationUtils.findAnnotation(job.getClazz(), CronExpress.class);
        if(cron != null && !"".equals(cron.value())) {
            // 注解的屬性,大于配置的屬性,方便調(diào)試
            job.setCron(cron.value());
        }
        job.setEnable(true);
        job.setActive(true);
        JobHandler entity = new JobHandler();
        TriggerTask triggerTask = new TriggerTask(runnable, (TriggerContext triggerContext) -> {
            // 每次任務執(zhí)行均會進入此方法
            CronTrigger trigger = new CronTrigger(job.getCron());
            entity.setTriggerContext(triggerContext);
            return job.isEnable() ? trigger.nextExecutionTime(triggerContext) : null;
        });
        ScheduledTask scheduledTask = registrar.scheduleTriggerTask(triggerTask);
        entity.setScheduledTask(scheduledTask);
        entity.setTriggerTask(triggerTask);
        tasks.put(job, entity);
        return job;
    }
 
    /**
     * 任務類(必須標注了@CronExpress注解,且實現(xiàn)了Runnable接口)
     * @param clazz 接口類
     * @return 任務對象
     */
    public Job addJob(Class<? extends Runnable> clazz) {
        Job job = new Job();
        job.setClazz(clazz);
        return this.addJob(job);
    }
 
    /**
     * 獲取任務操作對象
     * @param jobId 任務id
     * @return 任務操作對象
     */
    public JobHandler getJobHandler(String jobId) {
        return tasks.get(new Job(jobId));
    }
 
    /**
     * 根據(jù)任務id獲取任務
     * @param jobId 任務id
     * @return 任務實體
     */
    public Job getJob(String jobId) {
        Assert.hasText(jobId, "jobId can't be null");
        Set<Job> jobs = tasks.keySet();
        if(jobs.size() == 0) {
            return null;
        }
        Iterator<Job> iterator = jobs.iterator();
        while (iterator.hasNext()) {
            Job next = iterator.next();
            if(jobId.equals(next.getJobId())) {
                return next;
            }
        }
        return null;
    }
 
    /**
     * 關(guān)閉任務(若任務正在執(zhí)行,待任務執(zhí)行完)
     * @param jobId 任務id
     * @return 是否關(guān)閉成功
     */
    public boolean shutDown(String jobId) {
        try {
            JobHandler handler = this.getJobHandler(jobId);
            Assert.notNull(handler, "任務[" + jobId + "]不存在");
            handler.getScheduledTask().cancel();
            Job job = getJob(jobId);
            job.setActive(false);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
 
    /**
     * 啟動已經(jīng)注冊的任務
     * @param jobId 任務id
     * @return 是否成功啟動
     */
    public boolean startUp(String jobId) {
        try {
            JobHandler handler = this.getJobHandler(jobId);
            Assert.notNull(handler, "任務[" + jobId + "]不存在");
            register.getRegistrar().scheduleTriggerTask(handler.getTriggerTask());
            Job job = getJob(jobId);
            job.setActive(true);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
 
    /**
     * 獲取所有的任務實體
     * @return
     */
    public List<Job> getJobs() {
        return new ArrayList<>(tasks.keySet());
    }
 
    /**
     * 刪除任務,先關(guān)閉再刪除
     * @param jobId
     * @return
     */
    public boolean deleteJob(String jobId) {
        try {
            Job job = this.getJob(jobId);
            Assert.notNull(job, "任務[" + jobId + "]不存在");
            shutDown(jobId);
            tasks.remove(job);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
 
  • 任務運行類
@CronExpress("0/1 * * * * *")
public class HelloJob implements Runnable {
 
    @Override
    public void run() {
        System.out.println("hello msg" + Thread.currentThread().getId());
    }
}
  • 測試
ConfigurableApplicationContext ctx = SpringApplication.run(UnifiedTaskScheduleStarterApplication.class, args);
SchedulerManager schedulerManager = ctx.getBean(SchedulerManager.class);
Job job = schedulerManager.addJob(com.github.softwarevax.web.HelloJob.class);
schedulerManager.shutDown(job.getJobId());

三、使用 TaskScheduler

TaskScheduler 是Spring提供的用于調(diào)度任務的核心接口。通過 TaskScheduler,你可以靈活地安排任務的執(zhí)行時間,并且可以在運行時動態(tài)地創(chuàng)建、取消任務。

代碼示例簡單使用:

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 TaskSchedulerConfig {
 
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(5);
        scheduler.setThreadNamePrefix("MyScheduler-");
        return scheduler;
    }
}

在使用 TaskScheduler 時,可以通過 schedule 方法動態(tài)安排任務:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.stereotype.Component;
 
import java.util.Date;
 
@Component
public class DynamicTask {
 
    @Autowired
    private TaskScheduler taskScheduler;
 
    public void scheduleTask() {
        taskScheduler.schedule(() -> System.out.println("動態(tài)任務執(zhí)行:" + System.currentTimeMillis()), new Date(System.currentTimeMillis() + 5000));
    }
}

spring boot使用TaskScheduler實現(xiàn)動態(tài)增刪啟停定時任務

  • SchedulingConfig:添加執(zhí)行定時任務的線程池配置類
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();
        // 定時任務執(zhí)行線程池核心線程數(shù)
        taskScheduler.setPoolSize(4);
        taskScheduler.setRemoveOnCancelPolicy(true);
        taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
        return taskScheduler;
    }
}
  • ScheduledTask:添加ScheduledFuture的包裝類

ScheduledFuture是ScheduledExecutorService定時任務線程池的執(zhí)行結(jié)果。

import java.util.concurrent.ScheduledFuture;
 
public final class ScheduledTask {
 
    volatile ScheduledFuture<?> future;
 
    /**
     * 取消定時任務
     */
    public void cancel() {
        ScheduledFuture<?> future = this.future;
        if (future != null) {
            future.cancel(true);
        }
    }
}
  • SchedulingRunnable:添加Runnable接口實現(xiàn)類

添加Runnable接口實現(xiàn)類,被定時任務線程池調(diào)用,用來執(zhí)行指定bean里面的方法

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
 
import java.lang.reflect.Method;
import java.util.Objects;
 
public class SchedulingRunnable implements Runnable {
 
    private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);
 
    private final String beanName;
 
    private final String methodName;
 
    private final 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() {
        logger.info("定時任務開始執(zhí)行 - bean:{},方法:{},參數(shù):{}", beanName, methodName, params);
        long startTime = System.currentTimeMillis();
 
        try {
            Object target = SpringContextUtils.getBean(beanName);
 
            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) {
            logger.error(String.format("定時任務執(zhí)行異常 - bean:%s,方法:%s,參數(shù):%s ", beanName, methodName, params), ex);
        }
 
        long times = System.currentTimeMillis() - startTime;
        logger.info("定時任務執(zhí)行結(jié)束 - bean:{},方法:{},參數(shù):{},耗時:{} 毫秒", 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);
    }
}
  • CronTaskRegistrar:添加定時任務注冊類,用來增加、刪除定時任務
import com.example.testspringboot.cron.ScheduleResult;
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.*;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * 添加定時任務注冊類,用來增加、刪除定時任務。
 */
@Component
public class CronTaskRegistrar implements DisposableBean {
 
    private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);
    private final Map<Integer, ScheduleResult> schedulerJob = new HashMap<>();
 
    @Autowired
    private TaskScheduler taskScheduler;
 
    public TaskScheduler getScheduler() {
        return this.taskScheduler;
    }
 
    public void addCronTask(ScheduleResult scheduleResult) {
        SchedulingRunnable task = new SchedulingRunnable(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
        String cronExpression = scheduleResult.getCronExpression();
 
        CronTask cronTask = new CronTask(task, cronExpression);
        // 如果當前包含這個任務,則移除
        if (this.scheduledTasks.containsKey(task)) {
            removeCronTask(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
        }
        schedulerJob.put(scheduleResult.getJobId(), scheduleResult);
        this.scheduledTasks.put(task, scheduleCronTask(cronTask));
    }
 
    public void removeCronTask(String beanName, String methodName, String methodParams) {
        SchedulingRunnable task = new SchedulingRunnable(beanName, methodName, methodParams);
        ScheduledTask scheduledTask = this.scheduledTasks.remove(task);
        if (scheduledTask != null) {
            scheduledTask.cancel();
        }
    }
 
    public void removeCronTask(ScheduleResult scheduleResult) {
        schedulerJob.put(scheduleResult.getJobId(), scheduleResult);
        removeCronTask(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
    }
 
    public ScheduledTask scheduleCronTask(CronTask cronTask) {
        ScheduledTask scheduledTask = new ScheduledTask();
        scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
        return scheduledTask;
    }
 
    public Map<Runnable, ScheduledTask> getScheduledTasks() {
        return scheduledTasks;
    }
 
    public Map<Integer, ScheduleResult> getSchedulerJob() {
        return schedulerJob;
    }
 
    @Override
    public void destroy() {
        for (ScheduledTask task : this.scheduledTasks.values()) {
            task.cancel();
        }
 
        this.scheduledTasks.clear();
    }
 
    public ScheduleResult getSchedulerByJobId(Integer jobId) {
        for (ScheduleResult job : findAllTask()) {
            if (jobId.equals(job.getJobId())) {
                return job;
            }
        }
        return null;
    }
 
    public List<ScheduleResult> findAllTask() {
        List<ScheduleResult> ScheduleResults = new ArrayList<>();
        Set<Map.Entry<Integer, ScheduleResult>> entries = schedulerJob.entrySet();
        for (Map.Entry<Integer, ScheduleResult> en : entries) {
            ScheduleResults.add(en.getValue());
        }
        return ScheduleResults;
    }
}
  • CronUtils:校驗Cron表達式的有效性
import org.springframework.scheduling.support.CronExpression;
 
public class CronUtils {
 
    /**
     * 返回一個布爾值代表一個給定的Cron表達式的有效性
     *
     * @param cronExpression Cron表達式
     * @return boolean 表達式是否有效
     */
    public static boolean isValid(String cronExpression) {
        return CronExpression.isValidExpression(cronExpression);
    }
 
}
  • ScheduleResult:添加定時任務實體類
import lombok.Data;
 
@Data
public class ScheduleResult {
 
    /**
     * 任務ID
     */
    private Integer jobId;
 
    /**
     * bean名稱
     */
    private String beanName;
 
    /**
     * 方法名稱
     */
    private String methodName;
 
    /**
     * 方法參數(shù): 執(zhí)行service里面的哪一種方法
     */
    private String methodParams;
 
    /**
     * cron表達式
     */
    private String cronExpression;
 
    /**
     * 狀態(tài)(1正常 0暫停)
     */
    private Integer jobStatus;
 
    /**
     * 備注
     */
    private String remark;
 
    /**
     * 創(chuàng)建時間
     */
    private String createTime;
 
    /**
     * 更新時間
     */
    private String updateTime;
 
}
  • ScheduleJobStatus:任務狀態(tài)枚舉類型
public enum ScheduleJobStatus {
 
    /**
     * 暫停
     */
    PAUSE,
 
    /**
     * 正常
     */
    NORMAL;
 
}
  • SpringContextUtils類:從spring容器里獲取bean
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
 
@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;
        }
    }
 
    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);
 
    }
 
    public static boolean containsBean(String name) {
        return getApplicationContext().containsBean(name);
    }
 
    public static boolean isSingleton(String name) {
        return getApplicationContext().isSingleton(name);
    }
 
    public static Class<? extends Object> getType(String name) {
        return getApplicationContext().getType(name);
    }
}
  • ScheduleJobService:增刪啟停service方法
@Service
@Slf4j
public class ScheduleJobService {
 
    @Autowired
    private CronTaskRegistrar cronTaskRegistrar;
 
    public void addScheduleJob(ScheduleResult scheduleResult) {
        long currentTimeMillis = System.currentTimeMillis();
        scheduleResult.setCreateTime(formatTimeYMD_HMS_SSS(currentTimeMillis));
        scheduleResult.setUpdateTime(formatTimeYMD_HMS_SSS(currentTimeMillis));
        scheduleResult.setJobId(findAllTask().size() + 1);
        if (scheduleResult.getJobStatus().equals(ScheduleJobStatus.NORMAL.ordinal())) {
            log.info("Stop or pause: is now on");
            cronTaskRegistrar.addCronTask(scheduleResult);
            return;
        }
        cronTaskRegistrar.getSchedulerJob().put(scheduleResult.getJobId(), scheduleResult);
    }
 
    public void editScheduleJob(ScheduleResult currentSchedule) {
        //先移除
        cronTaskRegistrar.removeCronTask(currentSchedule.getBeanName(), currentSchedule.getMethodName(), currentSchedule.getMethodParams());
        ScheduleResult pastScheduleJob = cronTaskRegistrar.getSchedulerByJobId(currentSchedule.getJobId());
        if (pastScheduleJob == null) {
            System.out.println("沒有這個任務");
            return;
        }
        //然后判斷是否開啟, 如果開啟的話,現(xiàn)在立即執(zhí)行
        startOrStopSchedulerJob(currentSchedule, true);
    }
 
    public void deleteScheduleJob(ScheduleResult scheduleResult) {
        // 清除這個任務
        cronTaskRegistrar.removeCronTask(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
        // 清除這個任務的數(shù)據(jù)
        cronTaskRegistrar.getSchedulerJob().remove(scheduleResult.getJobId());
    }
 
    public void startOrStopScheduler(ScheduleResult scheduleResult) {
        cronTaskRegistrar.getSchedulerJob().get(scheduleResult.getJobId()).setJobStatus(scheduleResult.getJobStatus());
        startOrStopSchedulerJob(scheduleResult, false);
    }
 
    private void startOrStopSchedulerJob(ScheduleResult scheduleResult, boolean update) {
        // 更新時間
        scheduleResult.setUpdateTime(formatTimeYMD_HMS_SSS(System.currentTimeMillis()));
        if (scheduleResult.getJobStatus().equals(ScheduleJobStatus.NORMAL.ordinal())) {
            System.out.println("停止或暫停:現(xiàn)在是開啟");
            cronTaskRegistrar.addCronTask(scheduleResult);
            return;
        }
        System.out.println("停止或暫停:現(xiàn)在是暫停");
        if (update){
            cronTaskRegistrar.removeCronTask(scheduleResult);
            return;
        }
        cronTaskRegistrar.removeCronTask(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
    }
 
    public List<ScheduleResult> findAllTask() {
        return cronTaskRegistrar.findAllTask();
    }
 
 
    // 轉(zhuǎn)換為年-月-日 時:分:秒
    private String formatTimeYMD_HMS_SSS(long time) {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(time);
    }
}
  • cronController:訪問接口
import com.example.testspringboot.cron.ScheduleResult;
import com.example.testspringboot.cron.ScheduleJobService;
import com.example.testspringboot.cron.utils.CronUtils;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
 
import java.util.List;
 
@RestController
public class cronController {
 
    @Autowired
    private ScheduleJobService scheduleJobService;
 
    /**
     * 測試上傳的用例文件, 獲取詳細執(zhí)行結(jié)果
     */
    @PostMapping("/add")
    void executeTestOneFile(@RequestBody ScheduleResult scheduleResult) {
        boolean valid = CronUtils.isValid(scheduleResult.getCronExpression());
        if (valid){
            System.out.println("校驗成功, 添加任務");
            scheduleResult.setMethodParams(scheduleResult.getBranch()+scheduleResult.getCaseDir());
            scheduleJobService.addScheduleJob(scheduleResult);
        }else {
            System.out.println("校驗失敗");
        }
    }
 
    @PostMapping("/stop")
    void end(@RequestBody ScheduleResult scheduleResult) {
        Gson gson = new Gson();
        System.out.println("================");
        System.out.println(scheduleResult);
        System.out.println("=================");
        scheduleResult.setJobStatus(0);
        scheduleJobService.startOrStopScheduler(scheduleResult);
    }
 
    @PostMapping("/start")
    void start(@RequestBody ScheduleResult scheduleResult) {
        System.out.println("================");
        System.out.println(scheduleResult);
        System.out.println("=================");
        scheduleResult.setJobStatus(1);
        scheduleJobService.startOrStopScheduler(scheduleResult);
    }
 
    @PostMapping("/edit")
    void edit(@RequestBody ScheduleResult scheduleResult) {
        System.out.println("=======edit=========");
        System.out.println(scheduleResult);
        System.out.println("=================");
        scheduleJobService.editScheduleJob(scheduleResult);
    }
 
    @PostMapping("/delete")
    void delete(@RequestBody ScheduleResult scheduleResult) {
        System.out.println("=======delete=========");
        System.out.println(scheduleResult);
        System.out.println("=================");
        scheduleJobService.deleteScheduleJob(scheduleResult);
    }
 
    @GetMapping("/tasks")
    List<ScheduleResult> get() throws Exception {
        List<ScheduleResult> allTask = scheduleJobService.findAllTask();
        System.out.println("現(xiàn)在的定時任務數(shù)量 = " + allTask.size());
        System.out.println("現(xiàn)在的定時任務 = " + allTask);
        return allTask;
    }
}
  • 測試bean
import org.springframework.stereotype.Component;
 
@Component
public class c1 {
    public void test1(String y){
        System.out.println("這個是test1的bean : " + y);
    }
 
    public void test2(){
        System.out.println("這個是test1的bean中test2方法");
    }
}
  • 項目啟動后的定時任務
import com.example.testspringboot.cron.ScheduleJobService;
import com.example.testspringboot.cron.ScheduleResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
 
@Component
public class init  implements CommandLineRunner {
 
    @Autowired
    private ScheduleJobService scheduleJobService;
 
    @Override
    public void run(String... args) throws Exception {
        System.out.println("開始珍惜");
        ScheduleResult scheduleResult = new ScheduleResult();
        scheduleResult.setBeanName("c1");
        scheduleResult.setMethodName("test1");
        scheduleResult.setCronExpression("0/25 * * * * *");
        scheduleResult.setJobStatus(1);
        scheduleResult.setMethodParams("test1");
        scheduleJobService.addScheduleJob(scheduleResult);
        scheduleJobService.findAllTask();
    }
}

四、使用 Quartz 實現(xiàn)定時任務

Quartz 是一個功能強大的開源任務調(diào)度框架,支持復雜的任務調(diào)度需求,如任務的持久化、分布式任務管理、基于數(shù)據(jù)庫的調(diào)度等。Spring Boot 提供了對 Quartz 的良好集成,使得在應用中使用 Quartz 變得更加簡單。

簡單使用:

import org.quartz.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
 
@Configuration
public class QuartzConfig {
 
    @Bean
    public JobDetailFactoryBean jobDetail() {
        JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
        factoryBean.setJobClass(SampleJob.class);
        factoryBean.setDescription("Sample Quartz Job");
        factoryBean.setDurability(true);
        return factoryBean;
    }
 
    @Bean
    public SimpleTriggerFactoryBean trigger(JobDetail jobDetail) {
        SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
        factoryBean.setJobDetail(jobDetail);
        factoryBean.setRepeatInterval(5000); // 每5秒執(zhí)行一次
        factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
        return factoryBean;
    }
 
    public static class SampleJob implements Job {
        @Override
        public void execute(JobExecutionContext context) {
            System.out.println("Quartz任務執(zhí)行:" + System.currentTimeMillis());
        }
    }
}

springboot整合

  • 數(shù)據(jù)庫設(shè)計

將任務計劃放入數(shù)據(jù)庫中保存。在啟動任務是,從數(shù)據(jù)庫中查找任務計劃信息,并動態(tài)配置進去即可。

DROP TABLE IF EXISTS `cc_task_info`;
 
CREATE TABLE `cc_task_info` (
  `TID` int(11) NOT NULL AUTO_INCREMENT,
  `TASK_ANME` varchar(50) NOT NULL,
  `TASK_CODE` varchar(50) NOT NULL,
  `JOB_CLASS` varchar(200) NOT NULL,
  `JOB_GROUP` varchar(50) NOT NULL,
  `CRON` varchar(50) NOT NULL,
  `DEL_STATUS` varchar(2) DEFAULT '1' NULL,
  `CRT_TIME` datetime DEFAULT NULL,
  PRIMARY KEY (`TID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='定時任務管理表';
 
DROP TABLE IF EXISTS `cc_task_record`;
 
CREATE TABLE `cc_task_record` (
  `RID` int(11) NOT NULL AUTO_INCREMENT,
  `TASK_CODE` varchar(50) NOT NULL,
  `RUN_TIME` datetime NOT NULL,
  `RUN_CODE` char(1) NOT NULL,
  `RUN_MSG` varchar(100) NULL,
  PRIMARY KEY (`RID`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='定時任務運行記錄表';
 
DROP TABLE IF EXISTS `cc_task_status`;
 
CREATE TABLE `cc_task_status` (
  `TASK_CODE` varchar(50) NOT NULL,
  `TASK_STATUS` varchar(10) NOT NULL,
  `LST_SUCC_TIME` datetime NOT NULL,
  `LST_TIME` datetime NOT NULL,
  PRIMARY KEY (`TASK_CODE`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='定時任務運行狀態(tài)表';
  • 定時任務管理

通過Scheduler的方法來實現(xiàn)。Scheduler提供了一系列方法來管理定時任務的執(zhí)行狀態(tài)。

主要包括:

  • scheduleJob():添加定時任務
  • rescheduleJob():修改定時任務
  • pauseJob():暫停定時任務執(zhí)行
  • resumeJob():恢復定時任務執(zhí)行
  • deleteJob():刪除定時任務執(zhí)行

針對上述方法,只需要傳入對應參數(shù)即可。建了一個QuartzService來管理定時任務,供業(yè)務層調(diào)用。

詳細代碼如下:

/**
 * 定時任務管理服務
 */
@Service
public class QuartzService {
 
    public static String SCHEDULER_OPR_START = "start";
    public static String SCHEDULER_OPR_PAUSE = "pause";
    public static String SCHEDULER_OPR_RESUME = "resume";
    public static String SCHEDULER_OPR_REMOVE = "remove";
 
    @Autowired
    private Scheduler scheduler;
 
    /**
     * 啟動任務
     */
    public void startJob(String taskCode, String taskAnme, String cron, String jobGroup,
                         String className) throws Exception{
        Class<Job> jobClass = null;
        try {
            jobClass = (Class<Job>) Class.forName(className);//獲取任務執(zhí)行類
        } catch (ClassNotFoundException e) {
            throw new Exception("任務類不存在");
        }
        //創(chuàng)建job,指定job名稱和分組
        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(taskCode, jobGroup).build();
        //創(chuàng)建表達式工作計劃
        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
        //創(chuàng)建觸發(fā)器
        CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(taskCode, jobGroup)
                .withSchedule(cronScheduleBuilder).build();
        scheduler.scheduleJob(jobDetail, cronTrigger);
    }
 
    /**
     * 修改定時任務執(zhí)行時間
     * @param taskCode
     * @param jobGroup
     * @param cron 新的時間
     * @throws Exception
     */
    public void modifyJob(String taskCode, String jobGroup, String cron) throws Exception{
        TriggerKey triggerKey = new TriggerKey(taskCode, jobGroup);
        CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
        String oldCron = trigger.getCronExpression();
        if(!oldCron.equals(cron)){
            CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(taskCode, jobGroup)
                    .withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
            Date date = scheduler.rescheduleJob(triggerKey, cronTrigger);
            if(date == null){
                throw new Exception("修改定時任務執(zhí)行時間報錯");
            }
        }
    }
 
    /**
     * 暫停某個定時任務(任務恢復后,暫停時間段內(nèi)未執(zhí)行的任務會繼續(xù)執(zhí)行,如暫停時間段內(nèi)有2次,則會執(zhí)行2次)
     * @param taskCode
     * @param jobGroup
     * @throws Exception
     */
    public void pauseJob(String taskCode, String jobGroup) throws Exception{
        JobKey jobKey = new JobKey(taskCode, jobGroup);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if(jobDetail == null){
            return;
        }
        scheduler.pauseJob(jobKey);
    }
 
    /**
     * 恢復某個定時任務
     * @param taskCode
     * @param jobGroup
     * @throws Exception
     */
    public void resumeJob(String taskCode, String jobGroup) throws Exception{
        JobKey jobKey = new JobKey(taskCode, jobGroup);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if(jobDetail == null){
            return;
        }
        scheduler.resumeJob(jobKey);
    }
 
    /**
     * 刪除某個定時任務
     * @param taskCode
     * @param jobGroup
     * @throws Exception
     */
    public void deleteJob(String taskCode, String jobGroup) throws Exception{
        JobKey jobKey = new JobKey(taskCode, jobGroup);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if(jobDetail == null){
            return;
        }
        scheduler.deleteJob(jobKey);
    }
}
  • 編寫任務類JOB

任務類JOB就是定時任務具體要處理的系統(tǒng)業(yè)務邏輯,需要實現(xiàn)Job接口。

在任務啟動時,通過jobClass傳入JobDetail。

public class DemoJob implements Job {
 
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        String taskCode = jobExecutionContext.getJobDetail().getKey().getName();
        System.out.println("執(zhí)行定時任務:" + taskCode);
    }
}
  • 配置Scheduler

在Configuration中配置Scheduler實例,并啟動。

@Configuration
public class QuartzConfig {
 
    @Bean
    public Scheduler scheduler(){
        Scheduler scheduler = null;
        SchedulerFactory factory = new StdSchedulerFactory();
        try {
            scheduler = factory.getScheduler();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        if(scheduler != null){
            try {
                //啟動定時任務
                scheduler.start();
            } catch (SchedulerException e) {
                e.printStackTrace();
            }
        }
        return scheduler;
    }
}
  • 編寫API接口

通過Controller提供API接口,這里的TaskService調(diào)用了QartzService的對應接口,并做了一個寫數(shù)據(jù)庫讀寫操作,主要記錄定時任務狀態(tài)、執(zhí)行記錄信息的等。

@RestController
@RequestMapping("/api/task")
public class TaskController {
 
    @Autowired
    private TaskService service;
 
    @RequestMapping("/start")
    public Object start(int id){
        try {
            service.startJob(id);
            return RtnData.ok();
        } catch (Exception e) {
            return RtnData.fail(e.getMessage());
        }
    }
 
    @RequestMapping("/pause")
    public Object pause(int id){
        try {
            service.pauseJob(id);
            return RtnData.ok();
        } catch (Exception e) {
            return RtnData.fail(e.getMessage());
        }
    }
 
    @RequestMapping("/resume")
    public Object resume(int id){
        try {
            service.resumeJob(id);
            return RtnData.ok();
        } catch (Exception e) {
            return RtnData.fail(e.getMessage());
        }
    }
 
    @RequestMapping("/remove")
    public Object remove(int id){
        try {
            service.deleteJob(id);
            return RtnData.ok();
        } catch (Exception e) {
            return RtnData.fail(e.getMessage());
        }
    }
}

以上就是SpringBoot創(chuàng)建動態(tài)定時任務的幾種方式小結(jié)的詳細內(nèi)容,更多關(guān)于SpringBoot動態(tài)定時任務的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論