Up-to-date coverage of task executor and scheduler variants

Includes a clarification of ThreadPoolExecutor configuration options and a note on early AsyncConfigurer initialization.

Issue: SPR-16944
Issue: SPR-16945

(cherry picked from commit d58c09b)

(cherry picked from commit 5a11112)
This commit is contained in:
Juergen Hoeller
2018-06-29 19:43:14 +02:00
parent 1b0d838a19
commit d5bfddac69
4 changed files with 104 additions and 97 deletions

View File

@@ -478,7 +478,7 @@ shown in this example:
<entry key="/remoting/AccountService" value-ref="accountExporter"/>
</util:map>
</property>
<property name="port" value="8080" />
<property name="port" value="8080"/>
</bean>
----
@@ -2265,13 +2265,13 @@ containers that ships with Spring (in this case the `DefaultMessageListenerConta
[subs="verbatim,quotes"]
----
<!-- this is the Message Driven POJO (MDP) -->
<bean id="messageListener" class="jmsexample.ExampleListener" />
<bean id="messageListener" class="jmsexample.ExampleListener"/>
<!-- and this is the message listener container -->
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
**<property name="messageListener" ref="messageListener" />**
**<property name="messageListener" ref="messageListener"/>**
</bean>
----
@@ -2367,7 +2367,7 @@ POJO that we will make into an MDP via the following configuration.
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="destination" ref="destination"/>
**<property name="messageListener" ref="messageListener" />**
**<property name="messageListener" ref="messageListener"/>**
</bean>
----
@@ -2919,7 +2919,7 @@ describes all available attributes:
.Attributes of the JMS <listener> element
[cols="1,6"]
|===
| Attribute| Description
| Attribute | Description
| id
| A bean name for the hosting listener container. If not specified, a bean name will be
@@ -2990,7 +2990,7 @@ choices and message redelivery scenarios.
.Attributes of the JMS <listener-container> element
[cols="1,6"]
|===
| Attribute| Description
| Attribute | Description
| container-type
| The type of this listener container. Available options are: `default`, `simple`,
@@ -3443,7 +3443,7 @@ these registration behaviors are summarized on the following table:
.Registration Behaviors
[cols="1,4"]
|===
| Registration behavior| Explanation
| Registration behavior | Explanation
| `REGISTRATION_FAIL_ON_EXISTING`
| This is the default registration behavior. If an `MBean` instance has already been
@@ -3699,7 +3699,7 @@ metadata types:
.Source-level metadata parameters
[cols="1,3,1"]
|===
| Parameter| Description| Applies to
| Parameter | Description | Applies to
| `ObjectName`
| Used by `MetadataNamingStrategy` to determine the `ObjectName` of a managed resource
@@ -5085,7 +5085,7 @@ corresponding methods called on the CCI `Interaction` interface:
.Usage of Interaction execute methods
[cols="3,1,3"]
|===
| CciTemplate method signature| CciTemplate outputRecordCreator property| execute method called on the CCI Interaction
| CciTemplate method signature | CciTemplate outputRecordCreator property | execute method called on the CCI Interaction
| Record execute(InteractionSpec, Record)
| not set
@@ -5452,7 +5452,7 @@ The operation object approach uses records in the same manner as the `CciTemplat
.Usage of Interaction execute methods
[cols="3,1,3"]
|===
| MappingRecordOperation method signature| MappingRecordOperation outputRecordCreator property| execute method called on the CCI Interaction
| MappingRecordOperation method signature | MappingRecordOperation outputRecordCreator property | execute method called on the CCI Interaction
| Object execute(Object)
| not set
@@ -6225,49 +6225,37 @@ behavior, it is possible to use this abstraction for your own needs.
==== TaskExecutor types
There are a number of pre-built implementations of `TaskExecutor` included with the
Spring distribution. In all likelihood, you shouldn't ever need to implement your own.
Spring distribution. In all likelihood, you should never need to implement your own.
The common out-of-the-box variants are:
* `SyncTaskExecutor`
This implementation does not execute invocations asynchronously. Instead, each
invocation takes place in the calling thread. It is primarily used in situations
where multi-threading is not necessary such as in simple test cases.
* `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.
* `SyncTaskExecutor`
This implementation doesn't execute invocations asynchronously. Instead, each
invocation takes place in the calling thread. It is primarily used in situations
where multi-threading isn't necessary such as simple test cases.
are looking for true pooling, see `ThreadPoolTaskExecutor` below.
* `ConcurrentTaskExecutor`
This implementation is an adapter for a `java.util.concurrent.Executor` object.
This implementation is an adapter for a `java.util.concurrent.Executor` instance.
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` isn't flexible
enough for your needs, the `ConcurrentTaskExecutor` is an alternative.
* `SimpleThreadPoolTaskExecutor`
This implementation is actually a subclass of Quartz's `SimpleThreadPool` which
listens to Spring's 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.
configuration parameters as bean properties. There is rarely a need to use
`ConcurrentTaskExecutor` directly, but if the `ThreadPoolTaskExecutor` is not
flexible enough for your needs, then `ConcurrentTaskExecutor` is an alternative.
* `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.
* `WorkManagerTaskExecutor`
+
****
CommonJ is a set of specifications jointly developed between BEA and IBM. These
specifications are not Java EE standards, but are standard across BEA's and IBM's
Application Server implementations.
****
+
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.
This implementation uses a CommonJ `WorkManager` as its backing service provider
and is the central convenience class for setting up CommonJ-based thread pool
integration on WebLogic/WebSphere within a Spring application context.
* `DefaultManagedTaskExecutor`
This implementation uses a JNDI-obtained `ManagedExecutorService` in a JSR-236
compatible runtime environment such as a Java EE 7+ application server,
replacing a CommonJ WorkManager for that purpose.
[[scheduling-task-executor-usage]]
@@ -6295,7 +6283,6 @@ out a set of messages.
public void run() {
System.out.println(message);
}
}
private TaskExecutor taskExecutor;
@@ -6309,7 +6296,6 @@ out a set of messages.
taskExecutor.execute(new MessagePrinterTask("Message" + i));
}
}
}
----
@@ -6324,13 +6310,13 @@ been exposed.
[subs="verbatim,quotes"]
----
<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="queueCapacity" value="25" />
<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" />
<constructor-arg ref="taskExecutor"/>
</bean>
----
@@ -6358,7 +6344,6 @@ with a variety of methods for scheduling tasks to run at some point in the futur
ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);
}
----
@@ -6372,8 +6357,8 @@ much more flexible.
[[scheduling-trigger-interface]]
==== Trigger interface
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
The `Trigger` interface is essentially inspired by JSR-236 which, as of Spring 3.0,
was not yet 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
@@ -6385,7 +6370,6 @@ is quite simple:
public interface Trigger {
Date nextExecutionTime(TriggerContext triggerContext);
}
----
@@ -6404,7 +6388,6 @@ default). Here you can see what methods are available for `Trigger` implementati
Date lastActualExecutionTime();
Date lastCompletionTime();
}
----
@@ -6439,19 +6422,21 @@ could be configured externally and therefore easily modified or extended.
==== TaskScheduler implementations
As with Spring's `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.
arrangement is that an application's scheduling needs are decoupled from the deployment
environment. This abstraction level is particularly relevant when deploying to an
application server environment where threads should not be created directly by the
application itself. For such scenarios, Spring provides a `TimerManagerTaskScheduler`
delegating to a CommonJ TimerManager on WebLogic/WebSphere as well as a more recent
`DefaultManagedTaskScheduler` delegating to a JSR-236 `ManagedScheduledExecutorService`
in a Java EE 7+ environment, both typically configured with a JNDI lookup.
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
Spring's `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.
Whenever external thread management is not a requirement, a simpler alternative is
a local `ScheduledExecutorService` setup within the application which can be adapted
through Spring's `ConcurrentTaskScheduler`. As a convenience, Spring also provides a
`ThreadPoolTaskScheduler` which internally delegates to a `ScheduledExecutorService`,
providing common bean-style configuration along the lines of `ThreadPoolTaskExecutor`.
These variants work perfectly fine for locally embedded thread pool setups in lenient
application server environments as well, in particular on Tomcat and Jetty.
@@ -7217,12 +7202,12 @@ For more information on schema-based configuration, see <<xsd-configuration>>.
<!-- this is the bean definition for the Groovy-backed Messenger implementation -->
<lang:groovy id="messenger" script-source="classpath:Messenger.groovy">
<lang:property name="message" value="I Can Do The Frug" />
<lang:property name="message" value="I Can Do The Frug"/>
</lang:groovy>
<!-- an otherwise normal bean that will be injected by the Groovy-backed Messenger -->
<bean id="bookingService" class="x.y.DefaultBookingService">
<property name="messenger" ref="messenger" />
<property name="messenger" ref="messenger"/>
</bean>
</beans>
@@ -7336,11 +7321,11 @@ refreshable beans:
<lang:groovy id="messenger"
refresh-check-delay="5000" <!-- switches refreshing on with 5 seconds between checks -->
script-source="classpath:Messenger.groovy">
<lang:property name="message" value="I Can Do The Frug" />
<lang:property name="message" value="I Can Do The Frug"/>
</lang:groovy>
<bean id="bookingService" class="x.y.DefaultBookingService">
<property name="messenger" ref="messenger" />
<property name="messenger" ref="messenger"/>
</bean>
</beans>
@@ -7451,7 +7436,7 @@ feature crystal clear:
}
</lang:inline-script>
<lang:property name="message" value="I Can Do The Frug" />
<lang:property name="message" value="I Can Do The Frug"/>
</lang:groovy>
----
@@ -7490,7 +7475,7 @@ a `<![CDATA[]]>` region might be better.)
end
</lang:inline-script>
<lang:property name="message" value="Hello World!" />
<lang:property name="message" value="Hello World!"/>
</lang:jruby>
----
@@ -7535,10 +7520,10 @@ will __not__ work.
script-source="classpath:Messenger.groovy">
<!-- this next constructor argument will *not* be injected into the GroovyMessenger -->
<!-- in fact, this isn't even allowed according to the schema -->
<constructor-arg value="This will *not* work" />
<constructor-arg value="This will *not* work"/>
<!-- only property values are injected into the dynamic-language-backed object -->
<lang:property name="anotherMessage" value="Passed straight through to the dynamic-language-backed object" />
<lang:property name="anotherMessage" value="Passed straight through to the dynamic-language-backed object"/>
</lang>
----
@@ -7622,7 +7607,7 @@ And here is the Spring XML that defines an instance of the `RubyMessenger` JRuby
script-interfaces="org.springframework.scripting.Messenger"
script-source="classpath:RubyMessenger.rb">
<lang:property name="message" value="Hello World!" />
<lang:property name="message" value="Hello World!"/>
</lang:jruby>
----
@@ -7923,7 +7908,7 @@ term is used very loosely here).
<lang:bsh id="messageService" script-source="classpath:BshMessenger.bsh"
script-interfaces="org.springframework.scripting.Messenger">
<lang:property name="message" value="Hello World!" />
<lang:property name="message" value="Hello World!"/>
</lang:bsh>
----
@@ -8102,11 +8087,11 @@ a <<beans-factory-scopes-prototype,prototype>>.
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang.xsd">
<lang:groovy id="messenger" script-source="classpath:Messenger.groovy" scope="prototype">
<lang:property name="message" value="I Can Do The RoboCop" />
<lang:property name="message" value="I Can Do The RoboCop"/>
</lang:groovy>
<bean id="bookingService" class="x.y.DefaultBookingService">
<property name="messenger" ref="messenger" />
<property name="messenger" ref="messenger"/>
</bean>
</beans>
@@ -8715,8 +8700,7 @@ Alternatively for XML configuration use the `cache:annotation-driven` element:
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
<cache:annotation-driven />
<cache:annotation-driven/>
</beans>
----
@@ -8744,7 +8728,7 @@ javadoc for more details].
.Cache annotation settings
[cols="1,1,1,3"]
|===
| XML Attribute| Annotation Attribute| Default| Description
| XML Attribute | Annotation Attribute | Default | Description
| `cache-manager`
| N/A (See `CachingConfigurer` javadocs)
@@ -8927,7 +8911,7 @@ counterpart:
.Spring vs. JSR-107 caching annotations
[cols="1,1,3"]
|===
| Spring| JSR-107| Remark
| Spring | JSR-107 | Remark
| `@Cacheable`
| `@CacheResult`
@@ -9011,7 +8995,7 @@ the method again.
[subs="verbatim,quotes"]
----
@CacheResult(cacheName="books", **exceptionCacheName="failures"**
**cachedExceptions = InvalidIsbnNotFoundException.class**)
**cachedExceptions = InvalidIsbnNotFoundException.class**)
public Book findBook(ISBN isbn)
----
@@ -9140,11 +9124,11 @@ Again, to use it, one simply needs to declare the appropriate `CacheManager`:
[subs="verbatim,quotes"]
----
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
class="org.springframework.cache.ehcache.EhCacheCacheManager" p:cache-manager-ref="ehcache"/>
<!-- EhCache library setup -->
<bean id="ehcache"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="ehcache.xml"/>
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" p:config-location="ehcache.xml"/>
----
This setup bootstraps the ehcache library inside Spring IoC (through the `ehcache` bean) which
@@ -9165,7 +9149,7 @@ Configuring a `CacheManager` that creates the cache on demand is straightforward
[subs="verbatim,quotes"]
----
<bean id="cacheManager"
class="org.springframework.cache.caffeine.CaffeineCacheManager"/>
class="org.springframework.cache.caffeine.CaffeineCacheManager"/>
----
It is also possible to provide the caches to use explicitly. In that case, only those