Document TaskDecorator usage with TaskExecutors
Closes gh-33438
This commit is contained in:
parent
d1920c0982
commit
e9b0a19d3f
|
@ -50,6 +50,9 @@ The variants that Spring provides are as follows:
|
||||||
for each invocation. However, it does support a concurrency limit that blocks
|
for each invocation. However, it does support a concurrency limit that blocks
|
||||||
any invocations that are over the limit until a slot has been freed up. If you
|
any invocations that are over the limit until a slot has been freed up. If you
|
||||||
are looking for true pooling, see `ThreadPoolTaskExecutor`, later in this list.
|
are looking for true pooling, see `ThreadPoolTaskExecutor`, later in this list.
|
||||||
|
This will use JDK 21's Virtual Threads, when the "virtualThreads"
|
||||||
|
option is enabled. This implementation also supports graceful shutdown through
|
||||||
|
Spring's lifecycle management.
|
||||||
* `ConcurrentTaskExecutor`:
|
* `ConcurrentTaskExecutor`:
|
||||||
This implementation is an adapter for a `java.util.concurrent.Executor` instance.
|
This implementation is an adapter for a `java.util.concurrent.Executor` instance.
|
||||||
There is an alternative (`ThreadPoolTaskExecutor`) that exposes the `Executor`
|
There is an alternative (`ThreadPoolTaskExecutor`) that exposes the `Executor`
|
||||||
|
@ -61,15 +64,13 @@ The variants that Spring provides are as follows:
|
||||||
a `java.util.concurrent.ThreadPoolExecutor` and wraps it in a `TaskExecutor`.
|
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`,
|
If you need to adapt to a different kind of `java.util.concurrent.Executor`,
|
||||||
we recommend that you use a `ConcurrentTaskExecutor` instead.
|
we recommend that you use a `ConcurrentTaskExecutor` instead.
|
||||||
|
It also provides a pause/resume capability and graceful shutdown through
|
||||||
|
Spring's lifecycle management.
|
||||||
* `DefaultManagedTaskExecutor`:
|
* `DefaultManagedTaskExecutor`:
|
||||||
This implementation uses a JNDI-obtained `ManagedExecutorService` in a JSR-236
|
This implementation uses a JNDI-obtained `ManagedExecutorService` in a JSR-236
|
||||||
compatible runtime environment (such as a Jakarta EE application server),
|
compatible runtime environment (such as a Jakarta EE application server),
|
||||||
replacing a CommonJ WorkManager for that purpose.
|
replacing a CommonJ WorkManager for that purpose.
|
||||||
|
|
||||||
As of 6.1, `ThreadPoolTaskExecutor` provides a pause/resume capability and graceful
|
|
||||||
shutdown through Spring's lifecycle management. There is also a new "virtualThreads"
|
|
||||||
option on `SimpleAsyncTaskExecutor` which is aligned with JDK 21's Virtual Threads,
|
|
||||||
as well as a graceful shutdown capability for `SimpleAsyncTaskExecutor` as well.
|
|
||||||
|
|
||||||
|
|
||||||
[[scheduling-task-executor-usage]]
|
[[scheduling-task-executor-usage]]
|
||||||
|
@ -89,6 +90,22 @@ To configure the rules that the `TaskExecutor` uses, we expose simple bean prope
|
||||||
|
|
||||||
include-code::./TaskExecutorConfiguration[tag=snippet,indent=0]
|
include-code::./TaskExecutorConfiguration[tag=snippet,indent=0]
|
||||||
|
|
||||||
|
Most `TaskExecutor` implementations provide a way to automatically wrap tasks submitted
|
||||||
|
with a `TaskDecorator`. Decorators should delegate to the task it is wrapping, possibly
|
||||||
|
implementing custom behavior before/after the execution of the task.
|
||||||
|
|
||||||
|
Let's consider a simple implementation that will log messages before and after the execution
|
||||||
|
or our tasks:
|
||||||
|
|
||||||
|
include-code::./LoggingTaskDecorator[indent=0]
|
||||||
|
|
||||||
|
We can then configure our decorator on a `TaskExecutor` instance:
|
||||||
|
|
||||||
|
include-code::./TaskExecutorConfiguration[tag=decorator,indent=0]
|
||||||
|
|
||||||
|
In case multiple decorators are needed, the `org.springframework.core.task.support.CompositeTaskDecorator`
|
||||||
|
can be used to execute sequentially multiple decorators.
|
||||||
|
|
||||||
|
|
||||||
[[scheduling-task-scheduler]]
|
[[scheduling-task-scheduler]]
|
||||||
== The Spring `TaskScheduler` Abstraction
|
== The Spring `TaskScheduler` Abstraction
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2024 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.docs.integration.schedulingtaskexecutorusage;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import org.springframework.core.task.TaskDecorator;
|
||||||
|
|
||||||
|
public class LoggingTaskDecorator implements TaskDecorator {
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(LoggingTaskDecorator.class);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Runnable decorate(Runnable runnable) {
|
||||||
|
return () -> {
|
||||||
|
logger.debug("Before execution of " + runnable);
|
||||||
|
runnable.run();
|
||||||
|
logger.debug("After execution of " + runnable);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,4 +38,13 @@ public class TaskExecutorConfiguration {
|
||||||
return new TaskExecutorExample(taskExecutor);
|
return new TaskExecutorExample(taskExecutor);
|
||||||
}
|
}
|
||||||
// end::snippet[]
|
// end::snippet[]
|
||||||
|
|
||||||
|
// tag::decorator[]
|
||||||
|
@Bean
|
||||||
|
ThreadPoolTaskExecutor decoratedTaskExecutor() {
|
||||||
|
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
|
||||||
|
taskExecutor.setTaskDecorator(new LoggingTaskDecorator());
|
||||||
|
return taskExecutor;
|
||||||
|
}
|
||||||
|
// end::decorator[]
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2024 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.docs.integration.schedulingtaskexecutorusage
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log
|
||||||
|
import org.apache.commons.logging.LogFactory
|
||||||
|
import org.springframework.core.task.TaskDecorator
|
||||||
|
|
||||||
|
class LoggingTaskDecorator : TaskDecorator {
|
||||||
|
|
||||||
|
override fun decorate(runnable: Runnable): Runnable {
|
||||||
|
return Runnable {
|
||||||
|
logger.debug("Before execution of $runnable")
|
||||||
|
runnable.run()
|
||||||
|
logger.debug("After execution of $runnable")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val logger: Log = LogFactory.getLog(
|
||||||
|
LoggingTaskDecorator::class.java
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -34,4 +34,11 @@ class TaskExecutorConfiguration {
|
||||||
@Bean
|
@Bean
|
||||||
fun taskExecutorExample(taskExecutor: ThreadPoolTaskExecutor) = TaskExecutorExample(taskExecutor)
|
fun taskExecutorExample(taskExecutor: ThreadPoolTaskExecutor) = TaskExecutorExample(taskExecutor)
|
||||||
// end::snippet[]
|
// end::snippet[]
|
||||||
|
|
||||||
|
// tag::decorator[]
|
||||||
|
@Bean
|
||||||
|
fun decoratedTaskExecutor() = ThreadPoolTaskExecutor().apply {
|
||||||
|
setTaskDecorator(LoggingTaskDecorator())
|
||||||
|
}
|
||||||
|
// end::decorator[]
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,4 +15,13 @@
|
||||||
</bean>
|
</bean>
|
||||||
<!-- end::snippet[] -->
|
<!-- end::snippet[] -->
|
||||||
|
|
||||||
|
<!-- tag::decorator[] -->
|
||||||
|
<bean id="decoratedTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
|
||||||
|
<property name="taskDecorator" ref="loggingTaskDecorator"/>
|
||||||
|
</bean>
|
||||||
|
<!-- end::decorator[] -->
|
||||||
|
|
||||||
|
<bean id="loggingTaskDecorator" class="org.springframework.docs.integration.schedulingtaskexecutorusage.LoggingTaskDecorator">
|
||||||
|
</bean>
|
||||||
|
|
||||||
</beans>
|
</beans>
|
||||||
|
|
Loading…
Reference in New Issue