本文参考自Spring官方文档 34. Task Execution and Scheduling。
在程序中常常有定时任务的需求,例如每隔一周生成一次报表、每个月月末清空用户积分等等。Spring也提供了相应的支持,我们可以非常方便的按时执行任务。
项目准备
这里我使用Gradle来建立项目,然后在build.gradle
中添加下面一行。springVersion的值是目前最新的Spring版本'4.3.7.RELEASE'
。使用Maven的话也添加相应的行。spring-context会自动引入spring-core等几个最基本的依赖。
compile group: 'org.springframework', name: 'spring-context', version: springVersion
定时任务属于Spring的核心支持部分,所以我们不需要再添加其他的依赖了。所以定时任务功能既可以在命令行程序中使用,也可以在Java Web程序中使用。当然后者可能使用的更广泛一些(毕竟Web程序需要一直运行的嘛)。
这里我们定义两个任务,后面会让它们可以定时执行。
public interface IService {
void doService();
}
public class SimpleService implements IService {
@Override
public void doService() {
LocalTime time = LocalTime.now();
System.out.println("This is a simple service:" + time);
}
}
public class ExpensiveTaskService implements IService {
@Override
public void doService() {
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(1));
LocalTime time = LocalTime.now();
System.out.println("This is an expensive task:" + time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Spring的任务抽象
TaskExecutor
TaskExecutor
接口是任务执行接口,类似于java.util.concurrent.Executor
,该接口只有一个方法execute(Runnable task)
,用于执行任务。
Spring提供了一组TaskExecutor的实现,详细列表可以看这里34.2.1. TaskExecutor types。要使用它们也很简单,直接注册为Spring Bean,然后注入到程序中即可使用。
TaskScheduler
TaskScheduler
接口是定时器的抽象,它的源代码如下。可以看到,该接口包含了一组方法用于指定任务执行的时间。
public interface TaskScheduler {
ScheduledFuture schedule(Runnable task, Trigger trigger);
ScheduledFuture schedule(Runnable task, Date startTime);
ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period);
ScheduledFuture scheduleAtFixedRate(Runnable task, long period);
ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);
}
Spring提供了两个实现,一是TimerManagerTaskScheduler
,会将任务代理到CommonJ TimerManager实例。第二个是ThreadPoolTaskScheduler
,当我们不需要管理线程的时候就可以使用该类。而且它还同时实现了TaskExecutor
接口,所以一个ThreadPoolTaskScheduler
实例即可同时用于执行定时任务。
Trigger
在定时器接口的方法中我们可以发现一个方法接受Trigger接口, 而Trigger也是一个接口,抽象了触发任务执行的触发器。