Spring任务执行和调度

栏目: Java · 发布时间: 6年前

内容简介:1 概述Spring框架分别使用TaskExecutor和TaskScheduler接口提供异步执行和任务调度的抽象。Spring还提供了这些接口的实现,这些接口支持线程池或将其委托给应用服务器环境中的CommonJ。2 TaskExecutor
编辑推荐:
本文来自于csdn,本文主要介绍Spring框架在异步执行和任务调度方面的相关内容,希望对大家能有所帮助。

1 概述

Spring框架分别使用TaskExecutor和TaskScheduler接口提供异步执行和任务调度的抽象。Spring还提供了这些接口的实现,这些接口支持线程池或将其委托给应用服务器环境中的CommonJ。

2 TaskExecutor

Spring 2.0 开始引入的新的抽像。Executors 是线程池的 Java 5名称。之所以称作是“执行器”是因为不能保证底层实现实际上是一个池;执行程序可以是单线程的,甚至是同步的。Spring的TaskExecutor接口与java.util.concurrent是等价的。

2.1 TaskExecutor类型

SimpleAsyncTaskExecutor

线程不会重用,每次调用开启一个新的线程。支持并发,超过最大并发调用数时,会阻塞,直到释放一个槽为止。

SyncTaskExecutor

不会异步执行调用。每次调用都发生在调用线程中。它主要用于不需要多线程的情况。

ConcurrentTaskExecutor

Java 5 Java .util.concurrent. executor的包装。替代方案是ThreadPoolTaskExecutor,它将Executor配置参数作为bean属性公开。很少使用。

SimpleThreadPoolTaskExecutor

Quartz的SimpleThreadPool的一个子类,它监听Spring的生命周期回调。Quartz组件和非Quartz组件共享需要共享一个线程池时,通常会使用这种方法。

ThreadPoolTaskExecutor

只能在java5中使用。公开了用于配置java.util.concurrent的bean属性。如果需要高级的东西,比如ScheduledThreadPoolExecutor,建议使用ConcurrentTaskExecutor替代。

TimerTaskExecutor

通过TimerTask支撑实现。 不同于SyncTaskExecutor,因为方法调用在一个单独的线程中执行,尽管它们在那个线程中是同步的。

WorkManagerTaskExecutor

使用CommonJ WorkManager作为它的支持实现,并且是在Spring上下文中设置CommonJ WorkManager引用的中心便利类。与SimpleThreadPoolTaskExecutor类似,这个类实现了WorkManager接口,因此也可以直接作为WorkManager使用。

2.2 使用 TaskExecutor

 public class TaskExecutorExample {
 private class MessagePrinterTask implements Runnable {
 private String message;
 public MessagePrinterTask(String message) {
 this.message = message;
 }
 public void run() {
 System.out.println(message);
 }
 }
 private TaskExecutor taskExecutor;
 public TaskExecutorExample(TaskExecutor taskExecutor) {
 this.taskExecutor = taskExecutor;
 }
 public void printMessages() {
 for (int i = 0; i < 25; i++) {
 taskExecutor.execute(new MessagePrinterTask("Message" + i));
 }
 }
 }

与其从池中检索线程并自己执行,不如将Runnable添加到队列中,而TaskExecutor使用其内部规则来决定任务何时执行

配置TaskExecutor将使用的规则

 <bean id="taskExecutor" class="org.springframework.scheduling.concurrent
.ThreadPoolTaskExecutor">
 <property name="corePoolSize" value="5" />
 <property name="maxPoolSize" value="10" />
 <property name="queueCapacity" value="25" />
 </bean>
 <bean id="taskExecutorExample" class="cn.pconline.activity.task.TaskExecutorExample" init-method="printMessages">
 <constructor-arg ref="taskExecutor" />
 </bean>

3 TaskScheduler

除了任务执行者抽象之外。Spring 3.0还引入了一个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);
 }

名为“schedule”的方法,它只接受可运行的日期。这将导致任务在指定时间后运行一次。

所有其他方法都能够安排任务重复运行。固定速率和固定延迟方法用于简单的、周期性的执行,但是使用 Trigger 的方法要灵活得多。

3.1 Trigger

触发器的基本思想是,执行时间可以根据过去的执行结果甚至任意条件来确定。如果这些决定确实考虑了前面执行的结果,那么该信息在TriggerContext中是可用的。

public interface Trigger {

Date nextExecutionTime(TriggerContext triggerContext);

}

 public interface TriggerContext {
 Date lastScheduledExecutionTime();
 Date lastActualExecutionTime();
 Date lastCompletionTime();
 }

TriggerContext是最重要的部分。它封装了所有相关的数据,如果有必要,将来还可以进行扩展。TriggerContext是一个接口(默认情况下使用SimpleTriggerContext实现)。

3.2 Trigger 实现

Spring提供了触发器接口的两个实现。最有趣的是CronTrigger。它支持基于cron表达式的任务调度。

scheduler.schedule(task, new CronTrigger("* 15 9-17 * * MON-FRI"));

另一个开箱即用的实现是一个周期性Trigger ,它接受一个固定的周期、一个可选的初始延迟值,以及一个布尔值,用来指示周期应该解释为固定速率还是固定延迟。由于TaskScheduler接口已经定义了以固定速率或固定延迟调度任务的方法,因此应该尽可能直接使用这些方法。PeriodicTrigger实现的价值在于它可以在依赖于触发器抽象的组件中使用。例如,允许周期性Trigger 、基于cro的Trigger ,甚至自定义Trigger 实现可以互换使用,这可能很方便。这样的组件可以利用依赖注入,这样就可以在外部配置这样的Trigger 。

3.3 TaskScheduler实现

在应用服务器环境中,TaskScheduler提供的灵活性尤其重要。因为在这种环境中,线程不应该由应用程序本身直接创建。对于这种情况,Spring提供了一个TimerManagerTaskScheduler,它将委托给CommonJ TimerManager实例,通常配置为JNDI-lookup。

4 调度和异步执行的注解支持

4.1 开启scheduling 注解功能

为了支持@Scheduled和@Async注释,请将@EnableScheduling和@EnableAsync添加到@Configuration类中

@Configuration

@EnableAsync

@EnableSCheduling

public class AppConfig {

}

你可以自由选择应用程序的相关注释。例如,如果只需要支持@Scheduled,那么只需省略**@EnableAsync即可。对于更细粒度的控制,可以另外实现调度器和/或AsyncConfigurer**接口。

如果你更喜欢xml配置,这样配置。

<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>

<task:executor id="myExecutor" pool-size="5"/>

<task:scheduler id="myScheduler" pool-size="10"/>}

4.2 @Scheduled

@Scheduled添加到方法上

 //上一次调用完之后,五秒再调用一次,依此循环下去
 @Scheduled(fixedDelay=5000)
 public void doSomething() {
 // something that should execute periodically
 }
 //连续的每次调用开始时间之间,间隔5s
 @Scheduled(fixedRate=5000)
 public void doSomething() {
 // something that should execute periodically
 }
 //
 @Scheduled(cron="*/5 * * * * MON-FRI")
 public void doSomething() {
 // something that should execute on weekdays only
 }

值得注意的是调度的方法返回值必须是void,并且不能期望有任何参数。如果方法需要与来自应用程序上下文的其他对象交互,那么这些对象通常是通过依赖注入提供的。

4.3 @Async注解

添加了**@Async**注解的方法会异步执行。换句话说,方法调用后会立即返回,方法的实际执行将发生在提交给Spring TaskExecutor的任务中。

@Async

void doSomething() {

// this will be executed asynchronously

}

 /@Scheduled注释的方法不同,这些方法可以预期参数.
 //因为调用方将在运行时以“正常”方式调用它们,而不是从容器管理的调度任务中调用。
 @Async
 void doSomething(String s) {
 // this will be executed asynchronously
 }
 // 具有Future回调返回值
 //执行其它任务的优先级 依然是高于执行回调的优先级。
 @Async
 Future<String> returnSomething(int i) {
 // this will be executed asynchronously
 }

4.4 指定@Async注解的执行器

默认情况下,在方法上指定@Async时,将使用的执行器是提供“annotation-driven”元素的执行器,如上所述。然而,当需要指示在执行给定方法时应该使用非默认的执行器时,可以使用**@Async**注释的值属性。

 @Async("otherExecutor")
 void doSomething(String s) {
 // this will be executed asynchronously by "otherExecutor"
 }

5 Task 命名空间

从Spring 3.0开始,有一个用于配置TaskExecutor和TaskScheduler实例的XML名称空间。并提供了一种方便的方法,可以将任务配置为使用触发器进行调度。

5.1 scheduler 元素

<!-- 默认创建一个指定大小的ThreadPoolTaskScheduler -->

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

id属性用作线程池中线程的前缀名。如果不指定pool-size,默认的线程池中只有一个线程。

5.2 executor元素

<!-- 创建ThreadPoolTaskExecutor实例 -->

<task:executor id="executor" pool-size="10"/>

与上面的调度器一样,为’id’属性提供的值将用作池中线程名称的前缀。就池大小而言,'executor’元素比’scheduler’元素支持更多的配置选项。首先,ThreadPoolTaskExecutor的线程池本身是可配置的。执行程序的线程池可能对核心和最大大小有不同的值,而不仅仅是单个大小。如果提供了单个值,那么执行器将拥有一个固定大小的线程池(核心和最大大小相同)。然而,“executor”元素的“池大小”属性也接受“min-max”形式的范围。

<task:executor id="executorWithPoolSizeRange"

pool-size="5-25"

queue-capacity="100"/><!-- 指定队列的大小-->

 <task:executor id="executorWithCallerRunsPolicy"
 pool-size="5-25"
 queue-capacity="100"
 rejection-policy="CALLER_RUNS"/><!-- 任务拒绝策略(强制任务提交线程执行任务,从而限制传入负载变得过大) 默认的是直接抛出异常-->

5.3 scheduled-tasks元素

Spring task namespace 最强大的特性是支持在Spring应用程序上下文中配置要调度的任务。这与Spring中的其他“方法调用者”类似,例如JMS名称空间提供的配置消息驱动pojo的方法。

 <task:scheduled-tasks scheduler="myScheduler">
 <task:scheduled ref="beanA" method="methodA" fixed-delay="5000"/><!--ref
 指向容器管理的对象,method是要执行的方法名-->
 </task:scheduled-tasks>
 <task:scheduler id="myScheduler" pool-size="10"/>
 <task:scheduled-tasks scheduler="myScheduler">
 <task:scheduled ref="beanA" method="methodA" fixed-delay="5000" initial-delay="1000"/><!--第一次执行延迟一秒,以后每次上一个任务完成后 再执行-->
 <task:scheduled ref="beanB" method="methodB" fixed-rate="5000"/>
 <!--固定频率执行 如果上一个任务执行时间超时,第二个任务会立即执行 -->
 <task:scheduled ref="beanC" method="methodC" cron="*/5 * * * * MON-FRI"/>
 </task:scheduled-tasks>
 <task:scheduler id="myScheduler" pool-size="10"/>

6 Quartz Scheduler

Quartz使用触发器、作业和作业细节对象来实现各种作业的调度。有关Quartz背后的基本概念,请参阅http://quartz-scheduling er.org。为了方便起见,Spring提供了两个类,它们简化了基于Spring的应用程序中Quartz的使用。

6.1 使用JobDetailBean

JobDetail对象包含运行作业所需的所有信息。Spring框架提供了JobDetailBean,它使JobDetail更接近于具有合理默认值的实际JavaBean。

 <bean name="exampleJob" class="org.springframework.scheduling
.quartz.JobDetailBean">
 <property name="jobClass" value="example.ExampleJob" />
 <property name="jobDataAsMap">
 <map>
 <entry key="timeout" value="5" />
 </map>
 </property>
 </bean>

job detail bean 具有运行作业(ExampleJob)所需的所有信息。timeout在job data map指定。job data map可以通过JobExecutionContext(在执行时传递给您)获得,但是JobDetailBean还将 job data map 中的属性映射到实际job的属性。因此,在本例中,如果ExampleJob包含一个名为timeout的属性,JobDetailBean将自动应用它。

 package example;
 public class ExampleJob extends QuartzJobBean {
 private int timeout;
 /**
 * Setter called after the ExampleJob is instantiated
 * with the value from the JobDetailBean (5)
 */
 public void setTimeout(int timeout) {
 this.timeout = timeout;
 }
 protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
 // do the actual work
 }
 }

6.2 使用MethodInvokingJobDetailFactoryBean

使用MethodInvokingJobDetailFactoryBean你可以调用特定对象上的方法。

 <bean id="jobDetail" class="org.springframework.scheduling.quartz
.MethodInvokingJobDetailFactoryBean">
 <property name="targetObject" ref="exampleBusinessObject" />
 <property name="targetMethod" value="doIt" />
 </bean>
<bean id="exampleBusinessObject" class="examples.ExampleBusinessObject"/>

使用上面的配置将会导致ExampleBusinessObject .doIt()方法被调用。

 public class ExampleBusinessObject {
 // properties and collaborators
 public void doIt() {
 // do the actual work
 }
 }

使用MethodInvokingJobDetailFactoryBean,不再需要创建只调用一个方法的一行作业,只需要创建实际的业务对象并连接到它。

默认情况下,Quartz作业是无状态的,导致作业相互干扰的可能性。如果为相同的JobDetail指定两个触发器,那么可能在第一个作业完成之前,第二个作业就会开始。如果JobDetail类实现有状态接口,则不会发生这种情况。在第一项工作完成之前,第二项工作不会开始。要使方法调用jobdetailfactorybean产生的作业非并发,请将并发标志设置为false。

 <bean id="jobDetail" class="org.springframework.scheduling.quartz
.MethodInvokingJobDetailFactoryBean">
 <property name="targetObject" ref="exampleBusinessObject" />
 <property name="targetMethod" value="doIt" />
 <property name="concurrent" value="false" />
<!--并发执行false-->
 </bean>

6.3 作业调度

尽管我们能使用MethodInvokingJobDetailFactoryBean调用特定对象上的方法,但是我们还是需要调度作业 。这需要使用触发器和scheduler erfactorybean完成。Quartz 提供了多种触发器

Spring提供了两种Quartz 工厂对象:

CronTriggerFactoryBean

SimpleTriggerFactoryBean

两种触发器的示例

 <bean id="simpleTrigger" class="org.springframework.scheduling.quartz
.SimpleTriggerFactoryBean">
 <!-- see the example of method invoking job above -->
 <property name="jobDetail" ref="jobDetail" />
 <!-- 10 seconds -->
 <property name="startDelay" value="10000" />
 <!-- repeat every 50 seconds -->
 <property name="repeatInterval" value="50000" />
 </bean>
 <bean id="cronTrigger" class="org.springframework.scheduling.quartz
.CronTriggerFactoryBean">
 <property name="jobDetail" ref="exampleJob" />
 <!-- run every morning at 6 AM -->
 <property name="cronExpression" value="0 0 6 * * ?" />
<!-- 每天早上六点执行-->
 </bean>

关于SchedulerFactoryBean的等多属性设置 ,参考SchedulerFactoryBean javadoc


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Paradigms of Artificial Intelligence Programming

Paradigms of Artificial Intelligence Programming

Peter Norvig / Morgan Kaufmann / 1991-10-01 / USD 77.95

Paradigms of AI Programming is the first text to teach advanced Common Lisp techniques in the context of building major AI systems. By reconstructing authentic, complex AI programs using state-of-the-......一起来看看 《Paradigms of Artificial Intelligence Programming》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具