SpringBoot创建动态定时任务的几种方式
目录
一、使用@Scheduled注解
@Scheduled是 Spring 提供的一个注解,用于标记需要定时执行的方法。常见的属性包括:
- cron:通过 Cron 表达式定义任务的执行时间。
- fixedRate:定义任务的固定执行频率,以毫秒为单位。
- fixedDelay:定义任务在前一次执行完毕后延迟多少毫秒再执行。
代码示例:
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class ScheduledTasks {
@Scheduled(cron = "0 0 * * * ?") // 每小时整点执行一次
public void reportCurrentTime() {
System.out.println("现在时间:" + System.currentTimeMillis());
}
@Scheduled(fixedRate = 5000) // 每5秒执行一次
public void fixedRateTask() {
System.out.println("每5秒执行一次任务:" + System.currentTimeMillis());
}
@Scheduled(fixedDelay = 7000) // 前一次执行完毕后延迟7秒执行
public void fixedDelayTask() {
System.out.println("延迟7秒后执行任务:" + System.currentTimeMillis());
}
}
@Scheduled适用于大多数简单的定时任务场景,如定时发送邮件或生成报告等。然而,它的灵活性较差,对于复杂的任务调度需求,或需要动态调整任务时间的场景,可能并不适用。
二、使用SchedulingConfigurer接口
SchedulingConfigurer接口允许我们通过编程方式配置任务调度器(TaskScheduler)。通过实现这个接口,我们可以灵活地设置任务的调度规则,甚至动态地添加或移除任务。
简单使用代码:
public class TaskConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.addTriggerTask(
//1.添加任务内容(Runnable)
() -> System.out.println("执行定时任务2: " + LocalDateTime.now().toLocalTime()),
//2.设置执行周期(Trigger)
triggerContext -> {
//2.1 从数据库获取执行周期
String cron = zhyMapper.getCron();
//2.2 合法性校验.
if (StringUtils.isEmpty(cron)) {
// Omitted Code ..
}
//2.3 返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}
详细增删该查操作:
-
动态注册bean
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext CONTEXT; /** * 设置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动态注册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; /** * 是否处于等待执行下个任务的状态 */ 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; /** * 线程池任务调度器 */ @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())) { // 注解的属性,大于配置的属性,方便调试 job.setCron(cron.value()); } job.setEnable(true); job.setActive(true); JobHandler entity = new JobHandler(); TriggerTask triggerTask = new TriggerTask(runnable, (TriggerContext triggerContext) -> { // 每次任务执行均会进入此方法 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注解,且实现了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)); } /** * 根据任务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; } /** * 关闭任务(若任务正在执行,待任务执行完) * @param jobId 任务id * @return 是否关闭成功 */ 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; } } /** * 启动已经注册的任务 * @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()); } /** * 删除任务,先关闭再删除 * @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提供的用于调度任务的核心接口。通过TaskScheduler,你可以灵活地安排任务的执行时间,并且可以在运行时动态地创建、取消任务。
代码示例简单使用:
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方法动态安排任务:
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("动态任务执行:" + System.currentTimeMillis()), new Date(System.currentTimeMillis() + 5000));
}
}
spring boot使用TaskScheduler实现动态增删启停定时任务
-
SchedulingConfig:添加执行定时任务的线程池配置类
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-”);
???return taskScheduler;
???}
} -
ScheduledTask:添加ScheduledFuture的包装类
ScheduledFuture是ScheduledExecutorService定时任务线程池的执行结果。
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接口实现类
添加Runnable接口实现类,被定时任务线程池调用,用来执行指定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("定时任务开始执行 - bean:{},方法:{},参数:{}", 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("定时任务执行异常 - 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);
????}
}
-
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 findAllTask() {
???List 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;???/**
???* 方法参数: 执行service里面的哪一种方法
???*/
???private String methodParams;???/**
???* cron表达式
???*/
???private String cronExpression;???/**
???* 状态(1正常 0暂停)
???*/
???private Integer jobStatus;???/**
???* 备注
???*/
???private String remark;???/**
???* 创建时间
???*/
???private String createTime;???/**
???* 更新时间
???*/
???private String updateTime;}
-
ScheduleJobStatus:任务状态枚举类型
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 getBean(Class clazz) {
???return getApplicationContext().getBean(clazz);
???}???// 通过name,以及Clazz返回指定的Bean
???public static T getBean(String name, Class 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;
???}
???//然后判断是否开启, 如果开启的话,现在立即执行
???startOrStopSchedulerJob(currentSchedule, true);
???}???public void deleteScheduleJob(ScheduleResult scheduleResult) {
???// 清除这个任务
???cronTaskRegistrar.removeCronTask(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
???// 清除这个任务的数据
???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(“停止或暂停:现在是开启”);
???cronTaskRegistrar.addCronTask(scheduleResult);
???return;
???}
???System.out.println(“停止或暂停:现在是暂停”);
???if (update){
???cronTaskRegistrar.removeCronTask(scheduleResult);
???return;
???}
???cronTaskRegistrar.removeCronTask(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
???}???public List findAllTask() {
???return cronTaskRegistrar.findAllTask();
???}???// 转换为年-月-日 时:分:秒
???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;???/**
???* 测试上传的用例文件, 获取详细执行结果
???*/
???@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 get() throws Exception {
???List allTask = scheduleJobService.findAllTask();
???System.out.println("现在的定时任务数量 = " + allTask.size());
???System.out.println("现在的定时任务 = " + 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实现定时任务
Quartz是一个功能强大的开源任务调度框架,支持复杂的任务调度需求,如任务的持久化、分布式任务管理、基于数据库的调度等。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秒执行一次
factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
return factoryBean;
}
public static class SampleJob implements Job {
@Override
public void execute(JobExecutionContext context) {
System.out.println("Quartz任务执行:" + System.currentTimeMillis());
}
}
}
springboot整合
- 数据库设计
将任务计划放入数据库中保存。在启动任务是,从数据库中查找任务计划信息,并动态配置进去即可。
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='定时任务运行状态表';
- 定时任务管理
通过Scheduler的方法来实现。Scheduler提供了一系列方法来管理定时任务的执行状态。
主要包括:
- scheduleJob():添加定时任务
- rescheduleJob():修改定时任务
- pauseJob():暂停定时任务执行
- resumeJob():恢复定时任务执行
- deleteJob():删除定时任务执行
针对上述方法,只需要传入对应参数即可。建了一个QuartzService来管理定时任务,供业务层调用。
详细代码如下:
/**
?* 定时任务管理服务
?*/
@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);//获取任务执行类
????????} catch (ClassNotFoundException e) {
????????????throw new Exception("任务类不存在");
????????}
????????//创建job,指定job名称和分组
????????JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(taskCode, jobGroup).build();
????????//创建表达式工作计划
????????CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
????????//创建触发器
????????CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(taskCode, jobGroup)
????????????????.withSchedule(cronScheduleBuilder).build();
????????scheduler.scheduleJob(jobDetail, cronTrigger);
????}
????/**
?????* 修改定时任务执行时间
?????* @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("修改定时任务执行时间报错");
????????????}
????????}
????}
????/**
?????* 暂停某个定时任务(任务恢复后,暂停时间段内未执行的任务会继续执行,如暂停时间段内有2次,则会执行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就是定时任务具体要处理的系统业务逻辑,需要实现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("执行定时任务:" + 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调用了QartzService的对应接口,并做了一个写数据库读写操作,主要记录定时任务状态、执行记录信息的等。
@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());
????????}
????}
}
原文地址:https://blog.csdn.net/m0_74824802/article/details/145202644
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!