From 1dbe0ee6dbddc3cbf149c8a22f920a8e4107de1f Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 8 May 2023 12:02:25 +0200 Subject: [PATCH] Respect TaskDecorator configuration on DefaultManagedTaskExecutor Closes gh-30442 --- .../concurrent/ConcurrentTaskExecutor.java | 14 +++++-- .../concurrent/ConcurrentTaskScheduler.java | 11 +++--- .../ConcurrentTaskExecutorTests.java | 39 +++++++++++++++++-- 3 files changed, 52 insertions(+), 12 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java index 9c19aad566..f98b1e9faf 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -83,6 +83,9 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche private TaskExecutorAdapter adaptedExecutor; + @Nullable + private TaskDecorator taskDecorator; + /** * Create a new ConcurrentTaskExecutor, using a single thread executor as default. @@ -138,6 +141,7 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche * @since 4.3 */ public final void setTaskDecorator(TaskDecorator taskDecorator) { + this.taskDecorator = taskDecorator; this.adaptedExecutor.setTaskDecorator(taskDecorator); } @@ -174,11 +178,15 @@ public class ConcurrentTaskExecutor implements AsyncListenableTaskExecutor, Sche } - private static TaskExecutorAdapter getAdaptedExecutor(Executor concurrentExecutor) { + private TaskExecutorAdapter getAdaptedExecutor(Executor concurrentExecutor) { if (managedExecutorServiceClass != null && managedExecutorServiceClass.isInstance(concurrentExecutor)) { return new ManagedTaskExecutorAdapter(concurrentExecutor); } - return new TaskExecutorAdapter(concurrentExecutor); + TaskExecutorAdapter adapter = new TaskExecutorAdapter(concurrentExecutor); + if (this.taskDecorator != null) { + adapter.setTaskDecorator(this.taskDecorator); + } + return adapter; } diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java index 887c3f5965..577b7e2a00 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ConcurrentTaskScheduler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2023 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. @@ -100,7 +100,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T */ public ConcurrentTaskScheduler() { super(); - this.scheduledExecutor = initScheduledExecutor(null); + initScheduledExecutor(null); } /** @@ -115,7 +115,7 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T */ public ConcurrentTaskScheduler(ScheduledExecutorService scheduledExecutor) { super(scheduledExecutor); - this.scheduledExecutor = initScheduledExecutor(scheduledExecutor); + initScheduledExecutor(scheduledExecutor); } /** @@ -131,11 +131,11 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T */ public ConcurrentTaskScheduler(Executor concurrentExecutor, ScheduledExecutorService scheduledExecutor) { super(concurrentExecutor); - this.scheduledExecutor = initScheduledExecutor(scheduledExecutor); + initScheduledExecutor(scheduledExecutor); } - private ScheduledExecutorService initScheduledExecutor(@Nullable ScheduledExecutorService scheduledExecutor) { + private void initScheduledExecutor(@Nullable ScheduledExecutorService scheduledExecutor) { if (scheduledExecutor != null) { this.scheduledExecutor = scheduledExecutor; this.enterpriseConcurrentScheduler = (managedScheduledExecutorServiceClass != null && @@ -145,7 +145,6 @@ public class ConcurrentTaskScheduler extends ConcurrentTaskExecutor implements T this.scheduledExecutor = Executors.newSingleThreadScheduledExecutor(); this.enterpriseConcurrentScheduler = false; } - return this.scheduledExecutor; } /** diff --git a/spring-context/src/test/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutorTests.java b/spring-context/src/test/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutorTests.java index ca4a79d453..69f2f66e65 100644 --- a/spring-context/src/test/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutorTests.java +++ b/spring-context/src/test/java/org/springframework/scheduling/concurrent/ConcurrentTaskExecutorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2020 the original author or authors. + * Copyright 2002-2023 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. @@ -16,6 +16,7 @@ package org.springframework.scheduling.concurrent; +import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RunnableFuture; import java.util.concurrent.ThreadPoolExecutor; @@ -26,6 +27,8 @@ import org.junit.jupiter.api.Test; import org.springframework.core.task.AsyncListenableTaskExecutor; import org.springframework.core.task.NoOpRunnable; +import org.springframework.core.task.TaskDecorator; +import org.springframework.util.Assert; import static org.assertj.core.api.Assertions.assertThatCode; @@ -69,10 +72,40 @@ class ConcurrentTaskExecutorTests extends AbstractSchedulingTaskExecutorTests { } @Test - void passingNullExecutorToSetterResultsInDefaultTaskExecutorBeingUsed() { + void earlySetConcurrentExecutorCallRespectsConfiguredTaskDecorator() { ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor(); - executor.setConcurrentExecutor(null); + executor.setConcurrentExecutor(new DecoratedExecutor()); + executor.setTaskDecorator(new RunnableDecorator()); assertThatCode(() -> executor.execute(new NoOpRunnable())).doesNotThrowAnyException(); } + @Test + void lateSetConcurrentExecutorCallRespectsConfiguredTaskDecorator() { + ConcurrentTaskExecutor executor = new ConcurrentTaskExecutor(); + executor.setTaskDecorator(new RunnableDecorator()); + executor.setConcurrentExecutor(new DecoratedExecutor()); + assertThatCode(() -> executor.execute(new NoOpRunnable())).doesNotThrowAnyException(); + } + + + private static class DecoratedRunnable implements Runnable { + @Override + public void run() { + } + } + + private static class RunnableDecorator implements TaskDecorator { + @Override + public Runnable decorate(Runnable runnable) { + return new DecoratedRunnable(); + } + } + + private static class DecoratedExecutor implements Executor { + @Override + public void execute(Runnable command) { + Assert.state(command instanceof DecoratedRunnable, "TaskDecorator not applied"); + } + } + }