Spring Boot 动态添加/删除定时任务

实现目标

应用程序在运行期间动态添加、删除定时任务。

第一种定时任务实现方式-注解

@Configuration
@EnableScheduling
public class DemoTask {
	/**
	 * TODO: 每5秒执行一次
	 * @author FantasticTears
	 * @date 2020/9/25
	 */
	@Scheduled(cron = "*/5 * * * * *")
	public void cronTask() {
		System.out.println("每5秒执行一次");
	}
}

注解@Configuration告诉Spring启动时加载该类
注解@EnableScheduling启用计划任务
注解@Scheduled代表具体要执行的任务
Spring 具体加载机制和实现原理请自行研究Spring源码

很明显这种实现方式不符合本文的实现目标,因为这种任务在编译的时候间隔时间和实现的功能已经确定了。说这种实现方式目的是为了引出下一个话题ScheduledTaskRegistrar(注解@EnableScheduling源码上有注释)

ScheduledTaskRegistrar(注册类)

该类总共实现了三个接口ScheduledTaskHolder、InitializingBean、DisposableBean
主要接口是:InitializingBean

public interface InitializingBean {

	/**
	 * Invoked by the containing {@code BeanFactory} after it has set all bean properties
	 * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
	 * <p>This method allows the bean instance to perform validation of its overall
	 * configuration and final initialization when all bean properties have been set.
	 * @throws Exception in the event of misconfiguration (such as failure to set an
	 * essential property) or if initialization fails for any other reason
	 */
	void afterPropertiesSet() throws Exception;

}

该接口是Spring Bean 工厂完成Bean的创建工作后调用的一个方法,俗称Bean后置处理器。
这个类里边维护了应用程序所有的定时任务,大家可以去看下这个类的源码,具体的我就不再赘述了。
核心看下这个方法的实现afterPropertiesSet,这个方法会加载和初始化一下成员变量。
ScheduledTaskRegistrar部分源码
ScheduledTaskRegistrar部分源码

ScheduledAnnotationBeanPostProcessor

该类是通过查找ScheduledTaskRegistrar的引用找到的一个类,通过名称我们知道,该类就是处理注解Scheduled的具体实现。通过源码分析,其中有个方法finishRegistration,这个方法最后一行就调用了接口InitializingBeanafterPropertiesSet方法。

ScheduledAnnotationBeanPostProcessor部分源码

动态添加/删除任务实现

通过以上对Spring源码的分析我们总结出一个信息,那就是我们只要能拿到ScheduledTaskRegistrar对象,通过调用该对象的一些添加方法,最后调用一下afterPropertiesSet我们就能实现动态添加/删除任务的目标了。那么如何那到ScheduledTaskRegistrar对象呢,其实在注解EnableScheduling的注释里边已经有Demo了,实现SchedulingConfigurer接口即可。

@Configuration
public class DynamicTask implements SchedulingConfigurer {
	private static ScheduledTaskRegistrar scheduledTaskRegistrar;

	@Override
	public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
		log.info("定时任务注册器:{}", scheduledTaskRegistrar);
		DynamicTask.scheduledTaskRegistrar = scheduledTaskRegistrar;
	}

	/**
	 * TODO: 添加定时任务
	 * @author FantasticTears
	 * @date 2020/9/24
	 */
	public static void addScheduledTask(StudyTask studyTask, Check check) {
		List<CronTask> cronTaskList = scheduledTaskRegistrar.getCronTaskList();
		cronTaskList.forEach(v -> {
			if(v.getRunnable() instanceof StudyTask) {
				if(check.check((StudyTask) v.getRunnable())) {
					log.info("任务【{}】已在执行计划中!移除该任务并从新添加!", ((StudyTask) v.getRunnable()).getLearnTaskId());
					cronTaskList.remove(v);
				}
			}
		});
		if(studyTask.hasTask()) {
			scheduledTaskRegistrar.addCronTask(studyTask, "*/10 * * * * ?");
			scheduledTaskRegistrar.afterPropertiesSet();
		}
	}
}

特别注意

List<CronTask> cronTaskList = scheduledTaskRegistrar.getCronTaskList();
		cronTaskList.forEach(v -> {
			if(v.getRunnable() instanceof StudyTask) {
				if(check.check((StudyTask) v.getRunnable())) {
					log.info("任务【{}】已在执行计划中!移除该任务并从新添加!", ((StudyTask) v.getRunnable()).getLearnTaskId());
					cronTaskList.remove(v);
				}
			}
		});

这个代码在运行时会抛异常,写在这里就是给大家一个警示,删除任务不能通过这种方式实现,具体原因大家看下getCronTaskList这个方法的实现就知道了。
那么如何实现删除已经添加过的任务呢。答案是不能删除,只能取消执行

scheduledTaskRegistrar.getScheduledTasks().forEach(v -> {
			if(v.getTask() instanceof CronTask) {
				Task task = v.getTask();
				if(task.getRunnable() instanceof StudyTask) {
					if(check.check((StudyTask) task.getRunnable())) {
						log.info("任务【{}】已在执行计划中!移除该任务并从新添加!", ((StudyTask) task.getRunnable()).getLearnTaskId());
						v.cancel();
					}
				}
			}
		});

至此Spring Boot 定时任务动态添加/删除目标已完成!

结语。1


  1. Spring 源码我本身研究的也不多,有什么不对的地方欢迎大家提出,感谢大家的支持。 ↩︎

  • 8
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Spring Boot中,可以使用Spring自带的`@Scheduled`注解来实现定时任务。但是默认情况下,这些定时任务是在应用启动时就会被注册和执行的,无法动态地注册、删除、修改、添加。 为了实现定时任务动态管理,可以借助Quartz等第三方定时任务框架。下面是一种实现方案: 1. 引入Quartz依赖 在pom.xml中添加Quartz的依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> ``` 2. 配置Quartz定时任务 创建一个`QuartzConfig`类,配置Quartz的相关参数和实例化`Scheduler`对象: ```java @Configuration public class QuartzConfig { @Bean public Scheduler scheduler() throws SchedulerException { SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.start(); return scheduler; } } ``` 3. 创建定时任务 创建一个`Job`类,实现`org.quartz.Job`接口,并重写`execute`方法,定义具体的定时任务逻辑: ```java public class MyJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { // 定时任务逻辑 } } ``` 4. 注册定时任务 在需要注册定时任务的地方,获取`Scheduler`对象,并创建一个`JobDetail`和`Trigger`对象,将其注册到`Scheduler`中: ```java @Autowired private Scheduler scheduler; public void registerJob() throws SchedulerException { JobDetail jobDetail = JobBuilder.newJob(MyJob.class) .withIdentity("jobId", "groupName") .build(); Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("triggerId","groupName") .startNow() .withSchedule(CronScheduleBuilder.cronSchedule("*/5 * * * * ?")) .build(); scheduler.scheduleJob(jobDetail, trigger); } ``` 5. 实现动态管理 可以通过编程的方式,动态修改、删除添加定时任务。例如,可以通过`scheduler.deleteJob`方法删除已注册的定时任务;通过`JobBuilder.newJob`方法重新创建一个`JobDetail`,将其注册到`Scheduler`中实现修改或添加定时任务。 通过以上步骤的配置和实现,就可以在Spring Boot动态地注册、删除、修改、添加定时任务了。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值