前言

在开发SpringBoot项目的过程中,我们经常会遇到客户需要按照指定的时间执行一次业务的需求。如果客户需要改变业务的执行时间,即动态地调整定时任务的执行时间,那么可以采用SpringBoot自带的ScheduledTaskRegistrar类作为解决方案来实现。然而,单独使用ScheduledTaskRegistrar类可能无法达到预期的动态调整定时任务的效果。这时,我们需要灵活配合使用对应的工具类(如ThreadPoolTaskScheduler类),以方便地对动态调整定时任务进行管理。本文将从问题出发,详细介绍ScheduledTaskRegistrar类是如何解决动态调整定时任务的思路,并给出关键的代码示例,帮助大家快速地上手学习。

一、问题背景

在指定的某一时刻执行业务;

可以手动地更改执行时间。

在实际项目中,很少会有傻瓜式地去指定某一时间就触发某个业务的场景,执行业务的时间不是一成不变的,而是动态地随着客户所指定的时间进行调整的。

二、痛点所在

如果单一地使用SpringBoot自带的ScheduledTaskRegistrar去实现,那么可能会有以下问题:

1. 只能按照指定的时间去执行,更改执行时间需要重启服务;

2. 无法删除该定时任务,或者删除后无法再启动新的定时任务;

3. 业务逻辑与触发器的代码耦合度太高,无法将业务代码从ScheduledTaskRegistrar类中抽离出去;

4. 上述代码只能实现在指定的时间去触发定时任务,无法对cron表达式进行更改,如果更改则需要重新启动服务,非常地“傻瓜”。

而在实际的编码过程中,业务逻辑代码需要单独地剥离开(解耦),如何做到业务逻辑代码和触发器代码都能访问到外部业务数据,是设计过程中需要考虑到的关键。

三、解决思路

为了解决上述问题,我们可以引入一个名为ThreadPoolTaskScheduler类的工具类。通过源码得知,该类实现了SchedulingTaskExecutor和TaskScheduler接口。在这个实现类中,schedule(Runnable task, Trigger trigger)方法,通过分别传入Runnable任务和Trigger触发器,可以实现根据不同的触发策略来执行任务。这样一来,我们就可以在不重启服务的情况下动态地调整定时任务的执行时间了。同时,由于ThreadPoolTaskScheduler类与ScheduledTaskRegistrar类解耦,我们可以将业务逻辑代码和触发器代码分开编写,使得代码更加清晰易懂。

下面给出一个关键的代码示例:

```java

@Autowired

private ThreadPoolTaskScheduler threadPoolTaskScheduler;

public void startTask() {

TimerTask timerTask = new TimerTask() {

@Override

public void run() {

// 这里是需要执行的业务逻辑代码

}

};

Trigger trigger = new CronTrigger("0/5 * * * * ?"); // 每隔5秒执行一次

threadPoolTaskScheduler.schedule(timerTask, trigger);

}

```

在这个示例中,我们首先创建了一个TimerTask对象,用于存放需要执行的业务逻辑代码。然后,我们创建了一个CronTrigger对象,用于设置定时任务的执行策略(本例中为每隔5秒执行一次)。最后,我们调用threadPoolTaskScheduler的schedule方法,将TimerTask对象和Trigger对象传入,从而实现了动态地调整定时任务的执行时间。

线程任务(业务逻辑)和Trigger触发器对象作为参数,支持动态创建指定 cron 表达式的定时任务。

以下是对该方法的具体使用,核心思路如下:

1. 实例化ThreadPoolTaskScheduler类对象;

2. 实例化ScheduledFuture类对象,用于初始化调用schedule()后的值。将携带有Runnable和Trigger的ScheduledFuture类对象作为Map的value进行装配。根据Map的key对定时任务进行管理,达到添加和删除的目的。

四、代码示例

代码示例分为两部分:第一部分是关于ThreadPoolTaskScheduler类和schedule()方法的使用;第二部分是关于结合实际业务,引入实际业务数据的代码demo。

五、文章小结

动态定时任务的总结如下:单一使用ScheduledTaskRegistrar类,无法达到预期动态调整定时任务的效果。实际的开发场景中,需要业务逻辑代码和触发器代码都能访问到外部业务数据。配合ThreadPoolTaskScheduler类和该类中的schedule()方法可以达到动态调整定时任务的效果。