【Spring】Spring Framework Reference Documentation中文版31

34. Task Execution and Scheduling

执行任务和任务计划

 

34.1 Introduction

介绍

 

The Spring Framework provides abstractions for asynchronous execution and scheduling of tasks with the TaskExecutor and TaskScheduler interfaces, respectively. Spring also features implementations of those interfaces that support thread pools or delegation to CommonJ within an application server environment. Ultimately the use of these implementations behind the common interfaces abstracts away the differences between Java SE 5, Java SE 6 and Java EE environments.

spring框架提供了抽象用于异步的执行和计划任务使用TaskExecutorTaskScheduler接口。spring也提供了接口的实现来执行线程池或使用CommonJ在应用服务器的环境中。这些实现的背后是通用的接口抽象避免了JavaSE5JavaSE6JavaEE环境的不同。

 

Spring also features integration classes for supporting scheduling with the Timer, part of the JDK since 1.3, and the Quartz Scheduler ( http://quartz-scheduler.org). Both of those schedulers are set up using a FactoryBean with optional references to Timer or Trigger instances, respectively. Furthermore, a convenience class for both the Quartz Scheduler and the Timer is available that allows you to invoke a method of an existing target object (analogous to the normal MethodInvokingFactoryBean operation).

spring的特性集成类用于支持计划任务使用Timer,是JDK的一部分在1.3中被加入并且配合Quartz的计划任务()。这些都是用一个FactoryBean来设置引用Timer或触发器实例。此外,对于QuartzTimer还有一个方便的类允许你调用目标bean的方法对于已有的object(类似于正常的MethodInvokingFactoryBean操作)。

 

34.2 The Spring TaskExecutor abstraction

springTaskExecutor抽象

 

Spring 2.0 introduces a new abstraction for dealing with executors. Executors are the Java 5 name for the concept of thread pools. The "executor" naming is due to the fact that there is no guarantee that the underlying implementation is actually a pool; an executor may be single-threaded or even synchronous. Springs abstraction hides implementation details between Java SE 1.4, Java SE 5 and Java EE environments.

spring2.0引入了一个新的抽象用于处理执行器。ExecutorsJava5对于线程池的名字。executor意思是由于没有底层的实现实际是一个池;一个executor可以是单线程的或者是同步的。spring的抽象隐藏了实现细节在JavaSE1.4JavaSE5JavaEE的环境中。

 

Springs TaskExecutor interface is identical to the java.util.concurrent.Executor interface. In fact, its primary reason for existence was to abstract away the need for Java 5 when using thread pools. The interface has a single method execute(Runnable task) that accepts a task for execution based on the semantics and configuration of the thread pool.

springTaskExecutor接口和java.util.concurrent.Executor接口是相同的。实际上,他主要的存在时为了抽象对于Java5的需要当使用线程池的时候。接口有一个方法execute(Runnable task)接收一个任务用于执行在线程池的配置下。

 

The TaskExecutor was originally created to give other Spring components an abstraction for thread pooling where needed. Components such as the ApplicationEventMulticaster, JMSs AbstractMessageListenerContainer, and Quartz integration all use the TaskExecutor abstraction to pool threads. However, if your beans need thread pooling behavior, it is possible to use this abstraction for your own needs.

TaskExecutor通常创建给予其他的spring组件一个抽象对于线程池的需要。组件例如ApplicationEventMulticasterJMSAbstractMessageListenerContainerQuartz的集成都需要使用TaskExecutor抽象对于线程池。然而如果你的bean使用线程池的行为,将可以使用这个抽象根据你的需要。

 

34.2.1 TaskExecutor types

TaskExecutor类型

 

There are a number of pre-built implementations of TaskExecutor included with the Spring distribution. In all likelihood, you shouldnt ever need to implement your own.

有一部分已经构建号的实现对于TaskExecutor包含在spring的包中。在大部分情况下你可能不需要在单独进行实现。

 

    SimpleAsyncTaskExecutor This implementation does not reuse any threads, rather it starts up a new thread for each invocation. However, it does support a concurrency limit which will block any invocations that are over the limit until a slot has been freed up. If you are looking for true pooling, see the discussions of SimpleThreadPoolTaskExecutor and ThreadPoolTaskExecutor below.

SimpleAsyncTaskExecutor这个实现不重用任何线程,而是启动一个新的线程对于每次调用。然而,他支持并发的限制将阻塞任何调用如果超过限制直到有空间被释放。如果你需要池话,请参考下面的SimpleThreadPoolTaskExecutorThreadPoolTaskExecutor

    SyncTaskExecutor This implementation doesnt execute invocations asynchronously. Instead, each invocation takes place in the calling thread. It is primarily used in situations where multi-threading isnt necessary such as simple test cases.

SyncTaskExecutor这个实现不会异步执行。每个调用任务在调用的线程中。重要用于不需要多线程的简单测试情况下。

    ConcurrentTaskExecutor This implementation is an adapter for a java.util.concurrent.Executor object. There is an alternative, ThreadPoolTaskExecutor, that exposes the Executor configuration parameters as bean properties. It is rare to need to use the ConcurrentTaskExecutor, but if the ThreadPoolTaskExecutor isnt flexible enough for your needs, the ConcurrentTaskExecutor is an alternative.

ConcurrentTaskExecutor这个实现是一个适配器用于java.util.concurrent.Executorobject。这可以作为替代ThreadPoolTaskExecutor,暴露了Executor的配置参数作为bean的属性。他不需要使用ConcurrentTaskExecutor,但是如果ThreadPoolTaskExecutor不是足够的方便,你可以使用ConcurrentTaskExecutor作为替代。

    SimpleThreadPoolTaskExecutor This implementation is actually a subclass of Quartzs SimpleThreadPool which listens to Springs lifecycle callbacks. This is typically used when you have a thread pool that may need to be shared by both Quartz and non-Quartz components.

SimpleThreadPoolTaskExecutor这个实现是一个QuartzSimpleThreadPool的子类,监听spring的生命周期回调。

    ThreadPoolTaskExecutor This implementation is the most commonly used one. It exposes bean properties for configuring a java.util.concurrent.ThreadPoolExecutor and wraps it in a TaskExecutor. If you need to adapt to a different kind of java.util.concurrent.Executor, it is recommended that you use a ConcurrentTaskExecutor instead.

ThreadPoolTaskExecutor这个实现不经常被使用。他暴露bean的属性用于配置一个java.util.concurrent.ThreadPoolExecutor并且将其包裹进TaskExecutor中。如果你需要适配一个不同类型的java.util.concurrent.Executor,推荐你使用ConcurrentTaskExecutor作为替代。

 

    WorkManagerTaskExecutor

 

    CommonJ is a set of specifications jointly developed between BEA and IBM. These specifications are not Java EE standards, but are standard across BEAs and IBMs Application Server implementations.

CommonJ是一个规格的集合共同部署在BEAIBM之间。这个规范不是JavaEE标准的,但是标准的BEAIBM应用服务器的实现。

 

    This implementation uses the CommonJ WorkManager as its backing implementation and is the central convenience class for setting up a CommonJ WorkManager reference in a Spring context. Similar to the SimpleThreadPoolTaskExecutor, this class implements the WorkManager interface and therefore can be used directly as a WorkManager as well.

这个实现使用CommonJWorkManager作为他的后备实现并且是中心类用于设置CommonJWorkManager引用在spring的上下文中。类似于SimpleThreadPoolTaskExecutor,这个类实现了WorkManager接口并且可以直接使用作为一个WorkManager

 

34.2.2 Using a TaskExecutor

使用TaskExecutor

 

Springs TaskExecutor implementations are used as simple JavaBeans. In the example below, we define a bean that uses the ThreadPoolTaskExecutor to asynchronously print out a set of messages.

springTaskExecutor实现作为一个简单的JavaBean来使用。在下面的例子中,我们定义一个bean使用了ThreadPoolTaskExecutor来异步输出消息。

 

import org.springframework.core.task.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));

        }

    }

 

}

 

As you can see, rather than retrieving a thread from the pool and executing yourself, you add your Runnable to the queue and the TaskExecutor uses its internal rules to decide when the task gets executed.

你也看到,接收一个来自池的线程并且执行,你添加一个Runnable放入队列中并且TaskExecutor使用它内部的规则来决定什么时候开始任务。

 

To configure the rules that the TaskExecutor will use, simple bean properties have been exposed.

为了TaskExecutor将会使用的规则,简单的bean属性可以被暴露。

 

<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="TaskExecutorExample">

    <constructor-arg ref="taskExecutor" />

</bean>

 

34.3 The Spring TaskScheduler abstraction

springTaskExecutor抽象

 

In addition to the TaskExecutor abstraction, Spring 3.0 introduces a TaskScheduler with a variety of methods for scheduling tasks to run at some point in the future.

此外对于TaskExecutor抽象,spring3.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);

 

}

 

The simplest method is the one named 'schedule' that takes a Runnable and Date only. That will cause the task to run once after the specified time. All of the other methods are capable of scheduling tasks to run repeatedly. The fixed-rate and fixed-delay methods are for simple, periodic execution, but the method that accepts a Trigger is much more flexible.

简单的方法名字是叫schedule,只需要一个RunnableData。他将使得任务在指定时间只会执行一次。其他的所有方法是可以重复运行计划任务。固定频率和固定间隔方法用于简单的周期的执行但是方法接收一个Trigger是很方便的。

 

34.3.1 the Trigger interface

Trigger接口

 

The Trigger interface is essentially inspired by JSR-236, which, as of Spring 3.0, has not yet been officially implemented. The basic idea of the Trigger is that execution times may be determined based on past execution outcomes or even arbitrary conditions. If these determinations do take into account the outcome of the preceding execution, that information is available within a TriggerContext. The Trigger interface itself is quite simple:

Trigger接口是必要的来自JSR236spring3.0中没有提供官方的实现。Trigger的基本目的是执行此时决定给予过去的执行结果或一些条件。如果这些决定需要考虑之前的执行结果,在TriggerContext中的信息是有用的。Trigger接口本身是很简单的。

 

public interface Trigger {

 

    Date nextExecutionTime(TriggerContext triggerContext);

 

}

 

As you can see, the TriggerContext is the most important part. It encapsulates all of the relevant data, and is open for extension in the future if necessary. The TriggerContext is an interface (a SimpleTriggerContext implementation is used by default). Here you can see what methods are available for Trigger implementations.

你也看到TriggerContext是最重要的部分。他压缩所有相关的数据并且开放用于以后的扩展。TriggerContext是一个接口(一个默认使用的SimpleTriggerContext实现)。这里你可以看到方法是可以用于Trigger实现的。

 

public interface TriggerContext {

 

    Date lastScheduledExecutionTime();

 

    Date lastActualExecutionTime();

 

    Date lastCompletionTime();

 

}

 

34.3.2 Trigger implementations

Trigger实现

 

Spring provides two implementations of the Trigger interface. The most interesting one is the CronTrigger. It enables the scheduling of tasks based on cron expressions. For example, the following task is being scheduled to run 15 minutes past each hour but only during the 9-to-5 "business hours" on weekdays.

spring提供了两个实现对于Trigger接口。最有意思的是CronTrigger。他允许计划任务基于cron表达式。例如,下面的任务就是每15分钟执行并且是在工作日的9点到17点之间。

 

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

 

The other out-of-the-box implementation is a PeriodicTrigger that accepts a fixed period, an optional initial delay value, and a boolean to indicate whether the period should be interpreted as a fixed-rate or a fixed-delay. Since the TaskScheduler interface already defines methods for scheduling tasks at a fixed-rate or with a fixed-delay, those methods should be used directly whenever possible. The value of the PeriodicTrigger implementation is that it can be used within components that rely on the Trigger abstraction. For example, it may be convenient to allow periodic triggers, cron-based triggers, and even custom trigger implementations to be used interchangeably. Such a component could take advantage of dependency injection so that such Triggers could be configured externally and therefore easily modified or extended.

其他的实现是PeriodicTrigger接收一个固定的时间,可选初始延迟的值和一个布尔值用于指示是否可以被打断成为一个固定频率或固定延迟的任务。自从TaskScheduler接口已经定义了方法用于计划任务的执行以固定的速度或者固定的延迟,这些方法应当直接被使用。PeriodicTrigger实现的值是可以使用在组件中依赖于Trigger抽象。例如,他可以方便的允许周期的触发器、基于cron的触发器并且可以是自定义的触发器实现被使用。例如一个组件可以独立注入因此这样的触发器可以被外在配置并且简单的修改或继承。

 

34.3.3 TaskScheduler implementations

TaskScheduler实现

 

As with Springs TaskExecutor abstraction, the primary benefit of the TaskScheduler is that code relying on scheduling behavior need not be coupled to a particular scheduler implementation. The flexibility this provides is particularly relevant when running within Application Server environments where threads should not be created directly by the application itself. For such cases, Spring provides a TimerManagerTaskScheduler that delegates to a CommonJ TimerManager instance, typically configured with a JNDI-lookup.

由于springTaskExecutor抽象,TaskScheduler的主要意义是代码依赖于计划任务的行为不需要使用特定的计划实现。灵活性是特别相关的当使用在应用服务器环境中线程不应当被直接创建通过应用本身。对于这样的情况,spring提供了一个TimerManagerTaskScheduler委托给CommonJTimerManager实体,通常配置一个JNDI查找。

 

A simpler alternative, the ThreadPoolTaskScheduler, can be used whenever external thread management is not a requirement. Internally, it delegates to a ScheduledExecutorService instance. ThreadPoolTaskScheduler actually implements Springs TaskExecutor interface as well, so that a single instance can be used for asynchronous execution as soon as possible as well as scheduled, and potentially recurring, executions.

一个简单的替代是ThreadPoolTaskScheduler,可以被使用外部的线程管理单不是必须的。内部,他委托给ScheduledExecutorService实例。ThreadPoolTaskScheduler实际实现springTaskExecutor接口,因此一个简单的实例可以被使用用于异步执行根据计划任务并且可以重复使用。

 

34.4 Annotation Support for Scheduling and Asynchronous Execution

注解支持用于计划任务和异步执行

 

Spring provides annotation support for both task scheduling and asynchronous method execution.

spring提供了注解支持用于计划任务和异步的方法执行。

 

34.4.1 Enable scheduling annotations

允许计划注解

 

To enable support for @Scheduled and @Async annotations add @EnableScheduling and @EnableAsync to one of your @Configuration classes:

为了支持@Scheduled@Async注解添加@EnableScheduling@EnableAsync对于你的@Configuration类:

 

@Configuration

@EnableAsync

@EnableScheduling

public class AppConfig {

}

 

You are free to pick and choose the relevant annotations for your application. For example, if you only need support for @Scheduled, simply omit @EnableAsync. For more fine-grained control you can additionally implement the SchedulingConfigurer and/or AsyncConfigurer interfaces. See the javadocs for full details.

你可以使用相关的注解用于你的应用。例如,如果你需要@Scheduled的支持,简单的省略@EnableAsync。对于更加细节的控制你可以额外实现SchedulingConfigurer和或AsyncConfigurer接口。简单相关的javadocs来了解详情。

 

If you prefer XML configuration use the <task:annotation-driven> element.

如果你倾向xml的配置使用<task:annotation-driven>元素。

 

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

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

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

 

Notice with the above XML that an executor reference is provided for handling those tasks that correspond to methods with the @Async annotation, and the scheduler reference is provided for managing those methods annotated with @Scheduled.

注意上面的xml是一个executor引用被提供用于处理这些相关方法的任务使用@Async注解,并且计划引用被提供用于管理这些方法使用@Scheduled注解。

 

34.4.2 The @Scheduled annotation

@Scheduled注解

 

The @Scheduled annotation can be added to a method along with trigger metadata. For example, the following method would be invoked every 5 seconds with a fixed delay, meaning that the period will be measured from the completion time of each preceding invocation.

@Scheduled注解可以被添加到一个方法使用触发器的元数据。例如,下面的方法可以被每5秒钟调用异常使用一个固定的间隔,意味着可以被测量来自每个调用完成的时间。

 

@Scheduled(fixedDelay=5000)

public void doSomething() {

    // something that should execute periodically

}

 

If a fixed rate execution is desired, simply change the property name specified within the annotation. The following would be executed every 5 seconds measured between the successive start times of each invocation.

如果需要安装固定的速度来执行,简单的改变属性名执行在注解中。下面可以每5秒执行测量在每个调用开始的时间。

 

@Scheduled(fixedRate=5000)

public void doSomething() {

    // something that should execute periodically

}

 

For fixed-delay and fixed-rate tasks, an initial delay may be specified indicating the number of milliseconds to wait before the first execution of the method.

对于固定间隔和固定速率的任务,一个捏在的延迟可以指定为毫秒来等待第一个方法的执行。

 

@Scheduled(initialDelay=1000, fixedRate=5000)

public void doSomething() {

    // something that should execute periodically

}

 

If simple periodic scheduling is not expressive enough, then a cron expression may be provided. For example, the following will only execute on weekdays.

如果简单的周期计划任务是不会耗费太多,这样一个cron表达式可以被提供。例如,下面只会在工作日执行。

 

@Scheduled(cron="*/5 * * * * MON-FRI")

public void doSomething() {

    // something that should execute on weekdays only

}

 

[Tip]

提示

 

You can additionally use the zone attribute to specify the time zone in which the cron expression will be resolved.

你可以额外使用zone属性来指定时区用来解析cron表达式。

 

Notice that the methods to be scheduled must have void returns and must not expect any arguments. If the method needs to interact with other objects from the Application Context, then those would typically have been provided through dependency injection.

注意方法可以被计划必须是void的返回值并且不能有任何启动参数。如果方法需要配合其他的object来自应用上下文,则通常需要提供通过独立的注入。

 

[Note]

注意

 

As of Spring Framework 4.3, @Scheduled methods are supported on beans of any scope.

由于spring的框架4.3@Scheduled方法被支持在bean的任何范围中。

 

Make sure that you are not initializing multiple instances of the same @Scheduled annotation class at runtime, unless you do want to schedule callbacks to each such instance. Related to this, make sure that you do not use @Configurable on bean classes which are annotated with @Scheduled and registered as regular Spring beans with the container: You would get double initialization otherwise, once through the container and once through the @Configurable aspect, with the consequence of each @Scheduled method being invoked twice.

保证你不需要初始化相同的@Scheduled注解类在运行时,除非你希望计划任务回调每个实例。与此相关,保证你不会使用@Configurable注解在bean的类使用了@Scheduled注解并且注册为普通的springbean在容器中:你可以获得双重的初始化,通过容器和通过@Configurable的方面,使用每个@Scheduled方法的注解的结果可以被调用两次。

 

34.4.3 The @Async annotation

@Async注解

 

The @Async annotation can be provided on a method so that invocation of that method will occur asynchronously. In other words, the caller will return immediately upon invocation and the actual execution of the method will occur in a task that has been submitted to a Spring TaskExecutor. In the simplest case, the annotation may be applied to a void-returning method.

@Async注解可以被提供用于方法隐藏这个方法可以被异步的调用。换句话就是调用者将直接返回在调用时并且实际的方法的执行在一个任务中需要被提交给springTaskExecutor。在最简单的例子中,注解可以被应用于void返回的方法。

 

@Async

void doSomething() {

    // this will be executed asynchronously

}

 

Unlike the methods annotated with the @Scheduled annotation, these methods can expect arguments, because they will be invoked in the "normal" way by callers at runtime rather than from a scheduled task being managed by the container. For example, the following is a legitimate application of the @Async annotation.

不像使用@Scheduled注解的方法注解,这些方法可以有参数,因此她们将被调用以普通的方式通过调用者在运行时而不是计划任务由容器来管理。例如,下面是一个正常的应用使用了@Async注解。

 

@Async

void doSomething(String s) {

    // this will be executed asynchronously

}

 

Even methods that return a value can be invoked asynchronously. However, such methods are required to have a Future typed return value. This still provides the benefit of asynchronous execution so that the caller can perform other tasks prior to calling get() on that Future.

每个方法可以返回值被异步调用。然而,这样的方法需要有一个Future类型的返回值。这依然有异步执行的问题因此调用者可以执行其他的任务来调用Future中的get方法。

 

@Async

Future<String> returnSomething(int i) {

    // this will be executed asynchronously

}

 

[Tip]

提示

 

@Async methods may not only declare a regular java.util.concurrent.Future return type but also Springs org.springframework.util.concurrent.ListenableFuture or, as of Spring 4.2, JDK 8s java.util.concurrent.CompletableFuture: for richer interaction with the asynchronous task and for immediate composition with further processing steps.

@Async方法不只定义了一个普通的java.util.concurrent.Future的返回类型也包括springorg.springframework.util.concurrent.ListenableFuturespring4.2引入,还有JDK8java.util.concurrent.CompletableFuture:用于与异步任务相互作用用于直接作用于后续的处理步骤。

 

@Async can not be used in conjunction with lifecycle callbacks such as @PostConstruct. To asynchronously initialize Spring beans you currently have to use a separate initializing Spring bean that invokes the @Async annotated method on the target then.

@Async不能被用于生命周期的回调例如@PostConstruct。用于异步初始化springbean,你可以并发使用一个分离的初始化springbean调用@Async注解的方法在目标object上。

 

public class SampleBeanImpl implements SampleBean {

 

    @Async

    void doSomething() {

        // ...

    }

 

}

 

public class SampleBeanInitializer {

 

    private final SampleBean bean;

 

    public SampleBeanInitializer(SampleBean bean) {

        this.bean = bean;

    }

 

    @PostConstruct

    public void initialize() {

        bean.doSomething();

    }

 

}

 

[Note]

注意

 

There is no direct XML equivalent for @Async since such methods should be designed for asynchronous execution in the first place, not externally re-declared to be async. However, you may manually set up Springs AsyncExecutionInterceptor with Spring AOP, in combination with a custom pointcut.

没有直接的xml配置用于@Async因此这些方法应当被设计用于异步执行放在考虑的首位,不是直接声明为async。然而,你可以手动设置springAsyncExecutionInterceptor使用springAOP特性,用于自定义的切点。

 

34.4.4 Executor qualification with @Async

使用@AsyncExecutor的条件

 

By default when specifying @Async on a method, the executor that will be used is the one supplied to the 'annotation-driven' element as described above. However, the value attribute of the @Async annotation can be used when needing to indicate that an executor other than the default should be used when executing a given method.

默认指定一个方法为@Asyncexecutor将被使用来支持'annotation-driven'元素描述如上。然而,@Async注解的值可以被使用如果需要指定executor而不是使用默认的executor对于给定的方法。

 

@Async("otherExecutor")

void doSomething(String s) {

    // this will be executed asynchronously by "otherExecutor"

}

 

In this case, "otherExecutor" may be the name of any Executor bean in the Spring container, or may be the name of a qualifier associated with any Executor, e.g. as specified with the <qualifier> element or Springs @Qualifier annotation.

在这个情况下,"otherExecutor"可以是Executorbean的名字在spring的容器中或可以是全限定名对于任意的Executor,例如使用<qualifier>元素或spring@Qualifier注解来指定。

 

34.4.5 Exception management with @Async

使用@Async的异常管理

 

When an @Async method has a Future typed return value, it is easy to manage an exception that was thrown during the method execution as this exception will be thrown when calling get on the Future result. With a void return type however, the exception is uncaught and cannot be transmitted. For those cases, an AsyncUncaughtExceptionHandler can be provided to handle such exceptions.

当一个@Async方法有一个Future类型的返回值,就可以简单的管理方法执行时抛出的异常将会返回给获取Future结果的调用者。对于没有返回值的,异常不会被捕获并且不会被传递。对于这种情况,AsyncUncaughtExceptionHandler可以被提供来处理这样的异常。

 

public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {

 

    @Override

    public void handleUncaughtException(Throwable ex, Method method, Object... params) {

        // handle exception

    }

}

 

By default, the exception is simply logged. A custom AsyncUncaughtExceptionHandler can be defined via AsyncConfigurer or the task:annotation-driven XML element.

默认的,异常只是简单的被记录。一个自定义的AsyncUncaughtExceptionHandler可以被定义通过AsyncConfigurertask:annotation-drivenxml元素。

 

34.5 The task namespace

任务命名空间

 

Beginning with Spring 3.0, there is an XML namespace for configuring TaskExecutor and TaskScheduler instances. It also provides a convenient way to configure tasks to be scheduled with a trigger.

spring3.0开始,xml命名空间用于配置TaskExecutorTaskScheduler实例。他也提供了方便的方式用于配置任务通过触发器来执行。

 

34.5.1 The 'scheduler' element

scheduler元素

 

The following element will create a ThreadPoolTaskScheduler instance with the specified thread pool size.

下面的元素将创建一个ThreadPoolTaskScheduler实例使用指定的线程池数目。

 

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

 

The value provided for the 'id' attribute will be used as the prefix for thread names within the pool. The 'scheduler' element is relatively straightforward. If you do not provide a 'pool-size' attribute, the default thread pool will only have a single thread. There are no other configuration options for the scheduler.

id属性指定的值将被使用作为线程名的前缀。scheduler元素是相对简单的。如果你没有提供pool-size属性,默认的线程池将只有一个线程。对于scheduler没有其他的配置了。

 

34.5.2 The 'executor' element

executor元素

 

The following will create a ThreadPoolTaskExecutor instance:

下面的片段将创建一个ThreadPoolTaskExecutor实例:

 

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

 

As with the scheduler above, the value provided for the 'id' attribute will be used as the prefix for thread names within the pool. As far as the pool size is concerned, the 'executor' element supports more configuration options than the 'scheduler' element. For one thing, the thread pool for a ThreadPoolTaskExecutor is itself more configurable. Rather than just a single size, an executors thread pool may have different values for the core and the max size. If a single value is provided then the executor will have a fixed-size thread pool (the core and max sizes are the same). However, the 'executor' elements 'pool-size' attribute also accepts a range in the form of "min-max".

对于上面的scheduler,对于id属性指定的值将被使用作为线程池中线程名的前缀。对于线程池的大小,executor元素支持更多的配置比scheduler元素。用于ThreadPoolTaskExecutor的线程池是更加可配置的。而不是单一的数值,一个executor线程池可以有不同的值对于coremax。如果单个值被提供则executor将有一个固定大小的线程池(coremax是相同的)。然而,executor元素的pool-size属性也可以几首一个范围如min-max

 

<task:executor

        id="executorWithPoolSizeRange"

        pool-size="5-25"

        queue-capacity="100"/>

 

As you can see from that configuration, a 'queue-capacity' value has also been provided. The configuration of the thread pool should also be considered in light of the executors queue capacity. For the full description of the relationship between pool size and queue capacity, consult the documentation for ThreadPoolExecutor. The main idea is that when a task is submitted, the executor will first try to use a free thread if the number of active threads is currently less than the core size. If the core size has been reached, then the task will be added to the queue as long as its capacity has not yet been reached. Only then, if the queues capacity has been reached, will the executor create a new thread beyond the core size. If the max size has also been reached, then the executor will reject the task.

正如你看到的配置,queue-capacity值被提供。线程池的配置应当考虑在executor队列容量。对于pool sizequeue capacity之间的关系,参考ThreadPoolExecutor的文档。主要是任务的提交,executor将首先使用空闲的线程如果激活的线程数目小于core的大小。如果core的大小已经到达,则任务将被添加到队列中直到队列的容量已经满了。如果队列已经满了,executor将创建一个新的线程超过core的大小。如果max的大小也满足,则executor将拒绝这个任务。

 

By default, the queue is unbounded, but this is rarely the desired configuration, because it can lead to OutOfMemoryErrors if enough tasks are added to that queue while all pool threads are busy. Furthermore, if the queue is unbounded, then the max size has no effect at all. Since the executor will always try the queue before creating a new thread beyond the core size, a queue must have a finite capacity for the thread pool to grow beyond the core size (this is why a fixed size pool is the only sensible case when using an unbounded queue).

默认的,队里是无限的但是也依赖于响应的配置,因此他可能导致OutOfMemoryErrors如果有很多任务被加入到队列中当所有线程都忙碌的前提下。而且,如果队里是无限的,最大的数目是有影响的。因此executor将首先尝试保存任务到队列中而不是直接创建一个线程超过core的大小,一个队列必须有一个适当的容量(这就是为什么一个固定容量的线程池只是因为使用了一个无限容量的队列而已)。

 

In a moment, we will review the effects of the keep-alive setting which adds yet another factor to consider when providing a pool size configuration. First, lets consider the case, as mentioned above, when a task is rejected. By default, when a task is rejected, a thread pool executor will throw a TaskRejectedException. However, the rejection policy is actually configurable. The exception is thrown when using the default rejection policy which is the AbortPolicy implementation. For applications where some tasks can be skipped under heavy load, either the DiscardPolicy or DiscardOldestPolicy may be configured instead. Another option that works well for applications that need to throttle the submitted tasks under heavy load is the CallerRunsPolicy. Instead of throwing an exception or discarding tasks, that policy will simply force the thread that is calling the submit method to run the task itself. The idea is that such a caller will be busy while running that task and not able to submit other tasks immediately. Therefore it provides a simple way to throttle the incoming load while maintaining the limits of the thread pool and queue. Typically this allows the executor to "catch up" on the tasks it is handling and thereby frees up some capacity on the queue, in the pool, or both. Any of these options can be chosen from an enumeration of values available for the 'rejection-policy' attribute on the 'executor' element.

我们回顾keep-alive的设置添加另一个因素需要被考虑当提供一个池大小的配置时。首先,让我们考虑一下上面提到的当一个任务被拒绝。默认的当任务被拒绝,线程池的executor将抛出一个TaskRejectedException。然而拒绝策略是可以配置的。异常被抛出当使用默认的拒绝策略是AbortPolicy实现时。对于应用一些任务可能会超载,对于DiscardPolicyDiscardOldestPolicy可以被配置作为替代。另一个选项对于应用是需要减少任务的提交在高负载的前提下是CallerRunsPolicy。代替抛出一个异常或抛弃任务,此类将强制线程提交调用submit方法来执行任务。例如一个调用者将会忙碌的执行任务并且不会直接提交其他的任务。因此他提供了一个简单的方式来强制输入加载保证线程池和队列的大小。通常这允许executor来处理任务并且释放一些队列或线程池中的资源。任何选项可以被指定来自executor元素中的通过rejection-policy属性。

 

<task:executor

        id="executorWithCallerRunsPolicy"

        pool-size="5-25"

        queue-capacity="100"

        rejection-policy="CALLER_RUNS"/>

 

Finally, the keep-alive setting determines the time limit (in seconds) for which threads may remain idle before being terminated. If there are more than the core number of threads currently in the pool, after waiting this amount of time without processing a task, excess threads will get terminated. A time value of zero will cause excess threads to terminate immediately after executing a task without remaining follow-up work in the task queue.

最后keep-alive的设置决定了时间的限制(单位是秒)用于线程可以被保留空闲的时间在销毁之前。如果当前在池中的线程数目超过了core,在一段时间后没有处理任务,执行线程将被终止。如果设置为0则执行线程在任务结束后立刻终止而不需要等待一定的时间在任务队列中。

 

<task:executor

        id="executorWithKeepAlive"

        pool-size="5-25"

        keep-alive="120"/>

 

34.5.3 The 'scheduled-tasks' element

scheduled-tasks元素

 

The most powerful feature of Springs task namespace is the support for configuring tasks to be scheduled within a Spring Application Context. This follows an approach similar to other "method-invokers" in Spring, such as that provided by the JMS namespace for configuring Message-driven POJOs. Basically a "ref" attribute can point to any Spring-managed object, and the "method" attribute provides the name of a method to be invoked on that object. Here is a simple example.

spring任务命名空间中最有用的支持特性用于配置任务在spring的应用上下文中。他符合一定的规则相对比其他的"method-invokers"spring中,例如提供了JMS的命名空间用于配置消息驱动的POJO。基本的ref属性可以被指向任意的spring管理的object并且method属性提供了方法名被调用。这里是一个简单的例子。

 

<task:scheduled-tasks scheduler="myScheduler">

    <task:scheduled ref="beanA" method="methodA" fixed-delay="5000"/>

</task:scheduled-tasks>

 

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

 

As you can see, the scheduler is referenced by the outer element, and each individual task includes the configuration of its trigger metadata. In the preceding example, that metadata defines a periodic trigger with a fixed delay indicating the number of milliseconds to wait after each task execution has completed. Another option is 'fixed-rate', indicating how often the method should be executed regardless of how long any previous execution takes. Additionally, for both fixed-delay and fixed-rate tasks an 'initial-delay' parameter may be specified indicating the number of milliseconds to wait before the first execution of the method. For more control, a "cron" attribute may be provided instead. Here is an example demonstrating these other options.

正如你看到的,scheduler通过一个外部元素来引用并且每个独立的任务包含他触发器元数据的配置。在之前的例子中,元数据定义了一个周期性的触发器使用一个固定延迟指定单位为毫秒对于每个完成的任务。另一个选项是fixed-rate指示任务以什么样的频率来执行。此外,对于固定延迟和固定频率的任务,initia-delay参数可以被指定来指示等待的毫秒数在方法第一次执行之前。对于更多的控制,cron属性可以被提供作为替代。这是一个例子描述了这些选项。

 

<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"/>

 

34.6 Using the Quartz Scheduler

使用QuartzScheduler

 

Quartz uses Trigger, Job and JobDetail objects to realize scheduling of all kinds of jobs. For the basic concepts behind Quartz, have a look at http://quartz-scheduler.org. For convenience purposes, Spring offers a couple of classes that simplify the usage of Quartz within Spring-based applications.

Quartz使用TriggerJobJobDetail来描述所有种类的任务。对于基本的内容,请参考http://quartz-scheduler.org。为了方便,spring提供了一些类使得简单的使用Quartz在基于spring的应用中。

 

34.6.1 Using the JobDetailFactoryBean

使用JobDetailFactoryBean

 

Quartz JobDetail objects contain all information needed to run a job. Spring provides a JobDetailFactoryBean which provides bean-style properties for XML configuration purposes. Lets have a look at an example:

QuartzJobDetailobject包含所有你需要执行任务的信息。spring提供了一个JobDetailFactoryBean提供了一个bean风格的属性用于xml配置。让我们看一个例子:

 

<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">

    <property name="jobClass" value="example.ExampleJob"/>

    <property name="jobDataAsMap">

        <map>

            <entry key="timeout" value="5"/>

        </map>

    </property>

</bean>

 

The job detail configuration has all information it needs to run the job (ExampleJob). The timeout is specified in the job data map. The job data map is available through the JobExecutionContext (passed to you at execution time), but the JobDetail also gets its properties from the job data mapped to properties of the job instance. So in this case, if the ExampleJob contains a bean property named timeout, the JobDetail will have it applied automatically:

job的细节配置有需要运行job需要的全部信息。timeout被指定在jobdatamap中。jobdatamap通过JobExecutionContext(在执行时被传递),但是JobDetail也可以获取他的属性来自jobdata匹配job实例的属性。因此在这个例子中,如果ExampleJob包含一个bean属性名字为timeoutJobDetail将自动被应用。

 

package example;

 

public class ExampleJob extends QuartzJobBean {

 

    private int timeout;

 

    /**

     * Setter called after the ExampleJob is instantiated

     * with the value from the JobDetailFactoryBean (5)

     */

    public void setTimeout(int timeout) {

        this.timeout = timeout;

    }

 

    protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {

        // do the actual work

    }

 

}

 

All additional properties from the job data map are of course available to you as well.

所有额外的属性来自jobdatamap对于你也是可见的。

 

[Note]

注意

 

Using the name and group properties, you can modify the name and the group of the job, respectively. By default, the name of the job matches the bean name of the JobDetailFactoryBean (in the example above, this is exampleJob).

使用namegroup属性,你可以修改名字和job的组。默认的,job的名字匹配JobDetailFactoryBeanbean的名字(在上面的例子中是exampleJob)。

 

34.6.2 Using the MethodInvokingJobDetailFactoryBean

使用MethodInvokingJobDetailFactoryBean

 

Often you just need to invoke a method on a specific object. Using the MethodInvokingJobDetailFactoryBean you can do exactly this:

你只是需要调用指定object上的方法。使用MethodInvokingJobDetailFactoryBean你可以实现:

 

<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">

    <property name="targetObject" ref="exampleBusinessObject"/>

    <property name="targetMethod" value="doIt"/>

</bean>

 

The above example will result in the doIt method being called on the exampleBusinessObject method (see below):

上面的例子将导致在doIt方法中被调用exampleBusinessObject方法(见如下):

 

public class ExampleBusinessObject {

 

    // properties and collaborators

 

    public void doIt() {

        // do the actual work

    }

}

 

<bean id="exampleBusinessObject" class="examples.ExampleBusinessObject"/>

 

Using the MethodInvokingJobDetailFactoryBean, you dont need to create one-line jobs that just invoke a method, and you only need to create the actual business object and wire up the detail object.

使用MethodInvokingJobDetailFactoryBean,你不需要创建一次性的job就是为执行一个方法,并且你只需要创建实际的业务object和处理细节的object

 

By default, Quartz Jobs are stateless, resulting in the possibility of jobs interfering with each other. If you specify two triggers for the same JobDetail, it might be possible that before the first job has finished, the second one will start. If JobDetail classes implement the Stateful interface, this wont happen. The second job will not start before the first one has finished. To make jobs resulting from the MethodInvokingJobDetailFactoryBean non-concurrent, set the concurrent flag to false.

默认的,Quartz是无状态的,导致任务可以互相干涉。如果你指定了两个trigger用于相同的JobDetail,可能第一个任务刚完成,第二个将会开始。如果JobDetail类实现了Stateful接口就不会出现。第二个任务将不会启动在第一个任务完成之前。为了保证任务的结果来自MethodInvokingJobDetailFactoryBean,设置concurrent的标志为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"/>

</bean>

 

[Note]

注意

 

By default, jobs will run in a concurrent fashion.

默认的,job将会运行以并发的方式。

 

34.6.3 Wiring up jobs using triggers and the SchedulerFactoryBean

使用trigger来处理jobSchedulerFactoryBean

 

Weve created job details and jobs. Weve also reviewed the convenience bean that allows you to invoke a method on a specific object. Of course, we still need to schedule the jobs themselves. This is done using triggers and a SchedulerFactoryBean. Several triggers are available within Quartz and Spring offers two Quartz FactoryBean implementations with convenient defaults: CronTriggerFactoryBean and SimpleTriggerFactoryBean.

我们创建job的细节和job。我们也指定bean允许你来调用指定的object的方法。当然,我们依然需要计划任务本身。这是通过使用tiggger来实现和SchedulerFactoryBean。一些触发器是可以使用Quartz并且spring提供了两个QuartzFactoryBean实现使用的方便的默认实现:CronTriggerFactoryBeanSimpleTriggerFactoryBean

 

Triggers need to be scheduled. Spring offers a SchedulerFactoryBean that exposes triggers to be set as properties. SchedulerFactoryBean schedules the actual jobs with those triggers.

trigger需要被调度。spring提供了SchedulerFactoryBean来暴露触发器可以被设置为一个属性。SchedulerFactoryBean调度实际的job使用这些触发器。

 

Find below a couple of examples:

请参考下面的例子:

 

<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>

 

Now weve set up two triggers, one running every 50 seconds with a starting delay of 10 seconds and one every morning at 6 AM. To finalize everything, we need to set up the SchedulerFactoryBean:

下面我们设置了两个触发器,每50秒执行一次使用一个延迟为10秒并且在每天早上6点执行,我们需要设置SchedulerFactoryBean

 

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">

    <property name="triggers">

        <list>

            <ref bean="cronTrigger"/>

            <ref bean="simpleTrigger"/>

        </list>

    </property>

</bean>

 

More properties are available for the SchedulerFactoryBean for you to set, such as the calendars used by the job details, properties to customize Quartz with, etc. Have a look at the SchedulerFactoryBean javadocs for more information.

SchedulerFactoryBean可以设置更多的属性方便你来设置,例如calendars用于jobdetails,属性可以被自定义对于Quartz等等。请参考SchedulerFactoryBeanjavadocs来了解更多内容。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在Spring框架中,我们可以通过官方网站或者GitHub等方式下载到带有中文注释的源码。 首先,我们可以登录到Spring官方网站(https://spring.io/)上,在导航栏中点击"Projects",选择要下载的具体项目,例如"Spring Framework"。在项目的页面中,我们可以找到"Reference Documentation"一节,其中包含有关该项目的详细文档,包括中文版文档。我们可以点击文档链接,下载并查看带有中文注释的源码。 另外,我们还可以使用GitHub等代码托管平台来下载Spring框架的源码。在GitHub上,Spring项目有自己的组织(https://github.com/spring-projects),我们可以进入该组织,浏览并选择要下载的具体项目。在项目的页面中,我们可以找到"Clone or download"按钮,点击后可以选择下载源码的方式,例如使用Git命令行或者直接下载zip压缩包。下载完成后,我们可以解压源码包,即可得到带有中文注释的源码。 无论是从官方网站还是GitHub上下载Spring源码,都可以获取到带有中文注释的源代码文件。它们可以帮助我们更好地理解Spring框架的实现细节和使用方法,并为我们提供参考和学习的价值。 ### 回答2: 要下载Spring框架的中文注释源码,你可以按照以下步骤完成: 1. 打开Spring官方网站(https://spring.io/)的主页。 2. 在顶部的菜单中选择"Projects",然后点击"Spring Framework"。 3. 在Spring Framework的页面上,选择"下载"选项卡。 4. 在"下载"页面上,你会看到不同的版本可供选择。选择你需要的版本,通常建议选择最新的稳定版本。 5. 在所选版本的下载页面上,你会看到多个文件可供下载,包括二进制发行版、源代码和文档。这些文件通常以ZIP或JAR格式提供。 6. 找到带有"sources"或"src"标签的文件,这通常是指含有源代码的文件。点击下载链接,将源代码文件保存到你的计算机上。 7. 解压缩下载的源码文件,你将得到一个包含Spring框架所有模块源代码的文件夹。 8. 打开源代码文件夹并浏览其中的各个模块,你会发现所有源码文件都有中文注释。 通过以上步骤,你就可以下载并浏览到Spring框架中文注释的源码了。请记住,这些源码只是供学习和参考使用,并不建议对其进行修改或重新分发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值