Spring Task定时任务

Spring3.0以后引入的定时任务工具:spring task,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除spring相关的包外不需要额外的包,而且支持注解和配置文件两种。spring通过接口TaskExecutorTaskScheduler这两个接口的方式为异步定时任务提供了一种抽象。

XML配置

Spring提供了task命名空间,让配置定时任务非常简单。

1
2
3
4
5
6
7
<context:component-scan base-package="com.zsr.test.springTask"/>
<task:scheduler id="scheduler" pool-size="10" />
<task:scheduled-tasks scheduler="scheduler">
<task:scheduled ref="taskJob" method="execute" cron="0 * * * * ?"/>
</task:scheduled-tasks>

说明:ref参数指定的即任务类,method指定的即需要运行的方法,cron指定cronExpression表达式

注意:<task:schedule-tasks scheduler="scheduler"> 这里的scheduler必须显式指定,否则它只会使用默认的值,默认为单线程的。

任务Job

1
2
3
4
5
6
7
@Component
public class TaskJob {
public void execute() {
System.out.println("任务进行中.");
}
}

TaskExecutor

1
2
3
4
public interface TaskExecutor extends Executor {
@Override
void execute(Runnable task);
}

task:executor会注册一个ThreadPoolTaskExecutor执行器,可以使用它的相关属性来配置该执行器。

1
2
3
4
5
<task:executor
id="executor"
pool-size="10"
queue-capacity="100"
rejection-policy="CALLER_RUNS"/>
  • pool-size:线程池大小,如果只是设置了一个值。则corePoolsize和maxPoolSize都是这个值。
  • queue-capacity:队列大小
  • rejection-policy: 队列满的时候,使用的拒绝策略。

拒绝策略有:

  • ABORT(默认):抛出TaskRejectedException异常,然后不执行
  • DISCARD:不执行,也不抛出异常
  • DISCARD_OLDEST:丢弃queue中最旧的那个任务
  • CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport implements SchedulingTaskExecutor {
// 初始化Executor
protected ExecutorService initializeExecutor(
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
BlockingQueue<Runnable> queue = createQueue(this.queueCapacity);
// 线程池,默认情况下类似于Executors.newFixedThreadPool()
ThreadPoolExecutor executor = new ThreadPoolExecutor(
this.corePoolSize, this.maxPoolSize, this.keepAliveSeconds, TimeUnit.SECONDS,
queue, threadFactory, rejectedExecutionHandler);
if (this.allowCoreThreadTimeOut) {
executor.allowCoreThreadTimeOut(true);
}
this.threadPoolExecutor = executor;
return executor;
}
}

默认情况下执行队列是无限的,可能会导致JVM使用完所有内存,因此最好指定一个确定的数值。

TaskScheduler

1
2
3
4
public interface TaskScheduler {
ScheduledFuture schedule(Runnable task, Trigger trigger);
......
}

task:scheduler会注册一个ThreadPoolTaskScheduler 定时器,它只有一个属性线程池大小。默认是1,我们需要根据任务的数量指定一个合适的大小。

1
2
<task:scheduler id="scheduler"
pool-size="10"/>

TaskScheduler就是为了提供定时任务的支持。TaskScheduler需要传入一个Runnable的任务做为参数,并指定需要周期执行的时间或者触发器,这样Runnable任务就可以周期性执行了。

ThreadPoolTaskScheduler实际上代理了jdk中的SchedulingTaskExecutor,并且也实现了TaskScheduler接口,所以一个ThreadPoolTaskScheduler实例即可同时用于执行定时任务(任务调度和执行都是该线程池)。

1
2
3
4
5
6
7
8
9
public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
implements TaskScheduler, SchedulingTaskExecutor {
protected ExecutorService initializeExecutor(
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
this.scheduledExecutor = createExecutor(this.poolSize, threadFactory, rejectedExecutionHandler);
return this.scheduledExecutor;
}
}

执行任务

使用<task:scheduled-tasks>指定要执行的Bean和方法即可执行任务。

1
2
3
4
5
<task:scheduler id="scheduler" pool-size="10" />
<task:scheduled-tasks scheduler="scheduler">
<task:scheduled ref="taskJob" method="execute" cron="0 * * * * ?"/>
</task:scheduled-tasks>

使用注解

@Schedule:调度任务

spring 2.5开始,可以方便的使用注解来声明bean,对于定时任务,同样提供了注解@Scheduled

1
2
3
4
5
6
public @interface Scheduled
{
public abstract String cron();
public abstract long fixedDelay();
public abstract long fixedRate();
}
  • cron:指定cron表达式
  • fixedDelay:表示从上一个任务完成开始到下一个任务开始的间隔,单位是毫秒。
  • fixedRate:表示从上一个任务开始到下一个任务开始的间隔,单位是毫秒。
注解配置
1
2
3
4
5
<!-- 任务调度器 -->
<task:scheduler id="scheduler" pool-size="10" />
<!--开启这个配置,spring才能识别@Scheduled注解, @Async注解-->
<task:annotation-driven scheduler="scheduler" proxy-target-class="true"/>

proxy-target-class="true":表示使用cglib代理

任务Job
1
2
3
4
5
6
7
8
@Component
public class TaskJob {
@Scheduled(cron = "0 * * * * ?")
public void execute() {
System.out.println("任务进行中.");
}
}

@Schedule注解表示该任务既由ThreadPoolTaskScheduler调度同时也有该线程池执行(与上面的xml配置作用相同)

@Async:异步任务

对于异步任务,可以使用注解@Async

1
2
3
4
public @interface Async {
String value() default "";
}

可以在注解的地方指定任务执行的线程池(作用与executor="executor"相同),方式:@Async("executor")

注解配置
1
2
3
4
5
<!-- 任务执行器 -->
<task:executor id="executor" pool-size="10"/>
<!--开启注解调度支持 @Async @Scheduled-->
<task:annotation-driven executor="executor" proxy-target-class="true"/>
任务Job
1
2
3
4
5
6
7
8
@Component
public class TaskJob {
@Async
public void execute() {
System.out.println("任务进行中.");
}
}

同时使用@Schedule @Async

有时候执行任务需要的时间比较长,可以让scheduler只做调度,而让 executor 来执行我们的任务

注解配置
1
2
3
4
5
6
7
8
9
10
11
12
<task:scheduler id="scheduler" pool-size="10" />
<!--配置定时任务-->
<task:scheduled-tasks scheduler="scheduler">
<task:scheduled ref="taskJob" method="execute" cron="0 * * * * ?"/>
</task:scheduled-tasks>
<!-- 任务执行器 -->
<task:executor id="executor" pool-size="10"/>
<!--开启注解调度支持 @Async @Scheduled-->
<task:annotation-driven executor="executor" scheduler="scheduler" proxy-target-class="true"/>

注意:上述XML配置信息,其中处理任务的executor引用配置,相当于@Async注解;管理任务的Scheduler相当于@Scheduled注解。

任务Job
1
2
3
4
5
6
7
8
@Component
public class TaskJob {
@Async
public void execute() {
System.out.println("任务进行中.");
}
}

这样子,execute的方法,就会由executor 线程池来执行了。

参考

Spring Task 使用

Spring 3实现定时任务

Spring的两种任务调度Scheduled和Async

热评文章