Harmonize WebSocket message broker to use Executor

This commit harmonizes the configuration of the WebSocket message
broker to use Executor rather than TaskExecutor as only the former
is enforced. This lets custom configuration to use a wider range
of implementations.

Closes gh-32129
This commit is contained in:
Stéphane Nicoll 2024-01-26 11:30:22 +01:00
parent 2fc8b13dd5
commit f526b23fd7
5 changed files with 78 additions and 79 deletions

View File

@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.BeanInitializationException;
@ -30,7 +31,6 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.context.SmartLifecycle; import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.event.SmartApplicationListener; import org.springframework.context.event.SmartApplicationListener;
import org.springframework.core.task.TaskExecutor;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.converter.ByteArrayMessageConverter; import org.springframework.messaging.converter.ByteArrayMessageConverter;
@ -158,7 +158,7 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
@Bean @Bean
public AbstractSubscribableChannel clientInboundChannel( public AbstractSubscribableChannel clientInboundChannel(
@Qualifier("clientInboundChannelExecutor") TaskExecutor executor) { @Qualifier("clientInboundChannelExecutor") Executor executor) {
ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel(executor); ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel(executor);
channel.setLogger(SimpLogging.forLog(channel.getLogger())); channel.setLogger(SimpLogging.forLog(channel.getLogger()));
@ -170,9 +170,9 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
} }
@Bean @Bean
public TaskExecutor clientInboundChannelExecutor() { public Executor clientInboundChannelExecutor() {
ChannelRegistration registration = getClientInboundChannelRegistration(); ChannelRegistration registration = getClientInboundChannelRegistration();
TaskExecutor executor = getTaskExecutor(registration, "clientInboundChannel-", this::defaultTaskExecutor); Executor executor = getExecutor(registration, "clientInboundChannel-", this::defaultExecutor);
if (executor instanceof ExecutorConfigurationSupport executorSupport) { if (executor instanceof ExecutorConfigurationSupport executorSupport) {
executorSupport.setPhase(getPhase()); executorSupport.setPhase(getPhase());
} }
@ -209,7 +209,7 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
@Bean @Bean
public AbstractSubscribableChannel clientOutboundChannel( public AbstractSubscribableChannel clientOutboundChannel(
@Qualifier("clientOutboundChannelExecutor") TaskExecutor executor) { @Qualifier("clientOutboundChannelExecutor") Executor executor) {
ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel(executor); ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel(executor);
channel.setLogger(SimpLogging.forLog(channel.getLogger())); channel.setLogger(SimpLogging.forLog(channel.getLogger()));
@ -221,9 +221,9 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
} }
@Bean @Bean
public TaskExecutor clientOutboundChannelExecutor() { public Executor clientOutboundChannelExecutor() {
ChannelRegistration registration = getClientOutboundChannelRegistration(); ChannelRegistration registration = getClientOutboundChannelRegistration();
TaskExecutor executor = getTaskExecutor(registration, "clientOutboundChannel-", this::defaultTaskExecutor); Executor executor = getExecutor(registration, "clientOutboundChannel-", this::defaultExecutor);
if (executor instanceof ExecutorConfigurationSupport executorSupport) { if (executor instanceof ExecutorConfigurationSupport executorSupport) {
executorSupport.setPhase(getPhase()); executorSupport.setPhase(getPhase());
} }
@ -250,11 +250,11 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
@Bean @Bean
public AbstractSubscribableChannel brokerChannel( public AbstractSubscribableChannel brokerChannel(
AbstractSubscribableChannel clientInboundChannel, AbstractSubscribableChannel clientOutboundChannel, AbstractSubscribableChannel clientInboundChannel, AbstractSubscribableChannel clientOutboundChannel,
@Qualifier("brokerChannelExecutor") TaskExecutor executor) { @Qualifier("brokerChannelExecutor") Executor executor) {
MessageBrokerRegistry registry = getBrokerRegistry(clientInboundChannel, clientOutboundChannel); MessageBrokerRegistry registry = getBrokerRegistry(clientInboundChannel, clientOutboundChannel);
ChannelRegistration registration = registry.getBrokerChannelRegistration(); ChannelRegistration registration = registry.getBrokerChannelRegistration();
ExecutorSubscribableChannel channel = (registration.hasTaskExecutor() ? ExecutorSubscribableChannel channel = (registration.hasExecutor() ?
new ExecutorSubscribableChannel(executor) : new ExecutorSubscribableChannel()); new ExecutorSubscribableChannel(executor) : new ExecutorSubscribableChannel());
registration.interceptors(new ImmutableMessageChannelInterceptor()); registration.interceptors(new ImmutableMessageChannelInterceptor());
channel.setLogger(SimpLogging.forLog(channel.getLogger())); channel.setLogger(SimpLogging.forLog(channel.getLogger()));
@ -263,18 +263,18 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
} }
@Bean @Bean
public TaskExecutor brokerChannelExecutor( public Executor brokerChannelExecutor(
AbstractSubscribableChannel clientInboundChannel, AbstractSubscribableChannel clientOutboundChannel) { AbstractSubscribableChannel clientInboundChannel, AbstractSubscribableChannel clientOutboundChannel) {
MessageBrokerRegistry registry = getBrokerRegistry(clientInboundChannel, clientOutboundChannel); MessageBrokerRegistry registry = getBrokerRegistry(clientInboundChannel, clientOutboundChannel);
ChannelRegistration registration = registry.getBrokerChannelRegistration(); ChannelRegistration registration = registry.getBrokerChannelRegistration();
TaskExecutor executor = getTaskExecutor(registration, "brokerChannel-", () -> { Executor executor = getExecutor(registration, "brokerChannel-", () -> {
// Should never be used // Should never be used
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); ThreadPoolTaskExecutor fallbackExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(0); fallbackExecutor.setCorePoolSize(0);
threadPoolTaskExecutor.setMaxPoolSize(1); fallbackExecutor.setMaxPoolSize(1);
threadPoolTaskExecutor.setQueueCapacity(0); fallbackExecutor.setQueueCapacity(0);
return threadPoolTaskExecutor; return fallbackExecutor;
}); });
if (executor instanceof ExecutorConfigurationSupport executorSupport) { if (executor instanceof ExecutorConfigurationSupport executorSupport) {
executorSupport.setPhase(getPhase()); executorSupport.setPhase(getPhase());
@ -282,19 +282,19 @@ public abstract class AbstractMessageBrokerConfiguration implements ApplicationC
return executor; return executor;
} }
private TaskExecutor defaultTaskExecutor() { private Executor defaultExecutor() {
return new TaskExecutorRegistration().getTaskExecutor(); return new TaskExecutorRegistration().getTaskExecutor();
} }
private static TaskExecutor getTaskExecutor(ChannelRegistration registration, private static Executor getExecutor(ChannelRegistration registration,
String threadNamePrefix, Supplier<TaskExecutor> fallback) { String threadNamePrefix, Supplier<Executor> fallback) {
return registration.getTaskExecutor(fallback, return registration.getExecutor(fallback,
executor -> setThreadNamePrefix(executor, threadNamePrefix)); executor -> setThreadNamePrefix(executor, threadNamePrefix));
} }
private static void setThreadNamePrefix(TaskExecutor taskExecutor, String name) { private static void setThreadNamePrefix(Executor executor, String name) {
if (taskExecutor instanceof CustomizableThreadCreator ctc) { if (executor instanceof CustomizableThreadCreator ctc) {
ctc.setThreadNamePrefix(name); ctc.setThreadNamePrefix(name);
} }
} }

View File

@ -19,10 +19,10 @@ package org.springframework.messaging.simp.config;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.springframework.core.task.TaskExecutor;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.messaging.support.ChannelInterceptor; import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@ -41,7 +41,7 @@ public class ChannelRegistration {
private TaskExecutorRegistration registration; private TaskExecutorRegistration registration;
@Nullable @Nullable
private TaskExecutor executor; private Executor executor;
private final List<ChannelInterceptor> interceptors = new ArrayList<>(); private final List<ChannelInterceptor> interceptors = new ArrayList<>();
@ -67,14 +67,14 @@ public class ChannelRegistration {
} }
/** /**
* Configure the given {@link TaskExecutor} for this message channel, * Configure the given {@link Executor} for this message channel,
* taking precedence over a {@linkplain #taskExecutor() task executor * taking precedence over a {@linkplain #taskExecutor() task executor
* registration} if any. * registration} if any.
* @param taskExecutor the task executor to use * @param executor the executor to use
* @since 6.1.4 * @since 6.1.4
*/ */
public ChannelRegistration executor(TaskExecutor taskExecutor) { public ChannelRegistration executor(Executor executor) {
this.executor = taskExecutor; this.executor = executor;
return this; return this;
} }
@ -89,7 +89,7 @@ public class ChannelRegistration {
} }
protected boolean hasTaskExecutor() { protected boolean hasExecutor() {
return (this.registration != null || this.executor != null); return (this.registration != null || this.executor != null);
} }
@ -98,18 +98,17 @@ public class ChannelRegistration {
} }
/** /**
* Return the {@link TaskExecutor} to use. If no task executor has been * Return the {@link Executor} to use. If no executor has been configured,
* configured, the {@code fallback} supplier is used to provide a fallback * the {@code fallback} supplier is used to provide a fallback instance.
* instance.
* <p> * <p>
* If the {@link TaskExecutor} to use is suitable for further customizations, * If the {@link Executor} to use is suitable for further customizations,
* the {@code customizer} consumer is invoked. * the {@code customizer} consumer is invoked.
* @param fallback a supplier of a fallback task executor in case none is configured * @param fallback a supplier of a fallback executor in case none is configured
* @param customizer further customizations * @param customizer further customizations
* @return the task executor to use * @return the executor to use
* @since 6.1.4 * @since 6.2
*/ */
protected TaskExecutor getTaskExecutor(Supplier<TaskExecutor> fallback, Consumer<TaskExecutor> customizer) { protected Executor getExecutor(Supplier<Executor> fallback, Consumer<Executor> customizer) {
if (this.executor != null) { if (this.executor != null) {
return this.executor; return this.executor;
} }
@ -119,9 +118,9 @@ public class ChannelRegistration {
return registeredTaskExecutor; return registeredTaskExecutor;
} }
else { else {
TaskExecutor taskExecutor = fallback.get(); Executor fallbackExecutor = fallback.get();
customizer.accept(taskExecutor); customizer.accept(fallbackExecutor);
return taskExecutor; return fallbackExecutor;
} }
} }

View File

@ -16,12 +16,12 @@
package org.springframework.messaging.simp.config; package org.springframework.messaging.simp.config;
import java.util.concurrent.Executor;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.core.task.TaskExecutor;
import org.springframework.messaging.support.ChannelInterceptor; import org.springframework.messaging.support.ChannelInterceptor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@ -38,20 +38,20 @@ import static org.mockito.Mockito.verifyNoInteractions;
*/ */
class ChannelRegistrationTests { class ChannelRegistrationTests {
private final Supplier<TaskExecutor> fallback = mock(); private final Supplier<Executor> fallback = mock();
private final Consumer<TaskExecutor> customizer = mock(); private final Consumer<Executor> customizer = mock();
@Test @Test
void emptyRegistrationUsesFallback() { void emptyRegistrationUsesFallback() {
TaskExecutor fallbackTaskExecutor = mock(TaskExecutor.class); Executor fallbackExecutor = mock(Executor.class);
given(this.fallback.get()).willReturn(fallbackTaskExecutor); given(this.fallback.get()).willReturn(fallbackExecutor);
ChannelRegistration registration = new ChannelRegistration(); ChannelRegistration registration = new ChannelRegistration();
assertThat(registration.hasTaskExecutor()).isFalse(); assertThat(registration.hasExecutor()).isFalse();
TaskExecutor actual = registration.getTaskExecutor(this.fallback, this.customizer); Executor actual = registration.getExecutor(this.fallback, this.customizer);
assertThat(actual).isSameAs(fallbackTaskExecutor); assertThat(actual).isSameAs(fallbackExecutor);
verify(this.fallback).get(); verify(this.fallback).get();
verify(this.customizer).accept(fallbackTaskExecutor); verify(this.customizer).accept(fallbackExecutor);
} }
@Test @Test
@ -65,45 +65,45 @@ class ChannelRegistrationTests {
void taskRegistrationCreatesDefaultInstance() { void taskRegistrationCreatesDefaultInstance() {
ChannelRegistration registration = new ChannelRegistration(); ChannelRegistration registration = new ChannelRegistration();
registration.taskExecutor(); registration.taskExecutor();
assertThat(registration.hasTaskExecutor()).isTrue(); assertThat(registration.hasExecutor()).isTrue();
TaskExecutor taskExecutor = registration.getTaskExecutor(this.fallback, this.customizer); Executor executor = registration.getExecutor(this.fallback, this.customizer);
assertThat(taskExecutor).isInstanceOf(ThreadPoolTaskExecutor.class); assertThat(executor).isInstanceOf(ThreadPoolTaskExecutor.class);
verifyNoInteractions(this.fallback); verifyNoInteractions(this.fallback);
verify(this.customizer).accept(taskExecutor); verify(this.customizer).accept(executor);
} }
@Test @Test
void taskRegistrationWithExistingThreadPoolTaskExecutor() { void taskRegistrationWithExistingThreadPoolTaskExecutor() {
ThreadPoolTaskExecutor existingTaskExecutor = mock(ThreadPoolTaskExecutor.class); ThreadPoolTaskExecutor existingExecutor = mock(ThreadPoolTaskExecutor.class);
ChannelRegistration registration = new ChannelRegistration(); ChannelRegistration registration = new ChannelRegistration();
registration.taskExecutor(existingTaskExecutor); registration.taskExecutor(existingExecutor);
assertThat(registration.hasTaskExecutor()).isTrue(); assertThat(registration.hasExecutor()).isTrue();
TaskExecutor taskExecutor = registration.getTaskExecutor(this.fallback, this.customizer); Executor executor = registration.getExecutor(this.fallback, this.customizer);
assertThat(taskExecutor).isSameAs(existingTaskExecutor); assertThat(executor).isSameAs(existingExecutor);
verifyNoInteractions(this.fallback); verifyNoInteractions(this.fallback);
verify(this.customizer).accept(taskExecutor); verify(this.customizer).accept(executor);
} }
@Test @Test
void configureExecutor() { void configureExecutor() {
ChannelRegistration registration = new ChannelRegistration(); ChannelRegistration registration = new ChannelRegistration();
TaskExecutor taskExecutor = mock(TaskExecutor.class); Executor executor = mock(Executor.class);
registration.executor(taskExecutor); registration.executor(executor);
assertThat(registration.hasTaskExecutor()).isTrue(); assertThat(registration.hasExecutor()).isTrue();
TaskExecutor taskExecutor1 = registration.getTaskExecutor(this.fallback, this.customizer); Executor actualExecutor = registration.getExecutor(this.fallback, this.customizer);
assertThat(taskExecutor1).isSameAs(taskExecutor); assertThat(actualExecutor).isSameAs(executor);
verifyNoInteractions(this.fallback, this.customizer); verifyNoInteractions(this.fallback, this.customizer);
} }
@Test @Test
void configureExecutorTakesPrecedenceOverTaskRegistration() { void configureExecutorTakesPrecedenceOverTaskRegistration() {
ChannelRegistration registration = new ChannelRegistration(); ChannelRegistration registration = new ChannelRegistration();
TaskExecutor taskExecutor = mock(TaskExecutor.class); Executor executor = mock(Executor.class);
registration.executor(taskExecutor); registration.executor(executor);
ThreadPoolTaskExecutor ignored = mock(ThreadPoolTaskExecutor.class); ThreadPoolTaskExecutor ignored = mock(ThreadPoolTaskExecutor.class);
registration.taskExecutor(ignored); registration.taskExecutor(ignored);
assertThat(registration.hasTaskExecutor()).isTrue(); assertThat(registration.hasExecutor()).isTrue();
assertThat(registration.getTaskExecutor(this.fallback, this.customizer)).isSameAs(taskExecutor); assertThat(registration.getExecutor(this.fallback, this.customizer)).isSameAs(executor);
verifyNoInteractions(ignored, this.fallback, this.customizer); verifyNoInteractions(ignored, this.fallback, this.customizer);
} }

View File

@ -22,6 +22,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -31,7 +32,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.StaticApplicationContext; import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.task.TaskExecutor;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.messaging.Message; import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel; import org.springframework.messaging.MessageChannel;
@ -599,20 +599,20 @@ class MessageBrokerConfigurationTests {
@Override @Override
@Bean @Bean
public AbstractSubscribableChannel clientInboundChannel(TaskExecutor clientInboundChannelExecutor) { public AbstractSubscribableChannel clientInboundChannel(Executor clientInboundChannelExecutor) {
return new TestChannel(); return new TestChannel();
} }
@Override @Override
@Bean @Bean
public AbstractSubscribableChannel clientOutboundChannel(TaskExecutor clientOutboundChannelExecutor) { public AbstractSubscribableChannel clientOutboundChannel(Executor clientOutboundChannelExecutor) {
return new TestChannel(); return new TestChannel();
} }
@Override @Override
@Bean @Bean
public AbstractSubscribableChannel brokerChannel(AbstractSubscribableChannel clientInboundChannel, public AbstractSubscribableChannel brokerChannel(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel, TaskExecutor brokerChannelExecutor) { AbstractSubscribableChannel clientOutboundChannel, Executor brokerChannelExecutor) {
return new TestChannel(); return new TestChannel();
} }
} }
@ -688,21 +688,21 @@ class MessageBrokerConfigurationTests {
@Override @Override
@Bean @Bean
public AbstractSubscribableChannel clientInboundChannel(TaskExecutor clientInboundChannelExecutor) { public AbstractSubscribableChannel clientInboundChannel(Executor clientInboundChannelExecutor) {
// synchronous // synchronous
return new ExecutorSubscribableChannel(null); return new ExecutorSubscribableChannel(null);
} }
@Override @Override
@Bean @Bean
public AbstractSubscribableChannel clientOutboundChannel(TaskExecutor clientOutboundChannelExecutor) { public AbstractSubscribableChannel clientOutboundChannel(Executor clientOutboundChannelExecutor) {
return new TestChannel(); return new TestChannel();
} }
@Override @Override
@Bean @Bean
public AbstractSubscribableChannel brokerChannel(AbstractSubscribableChannel clientInboundChannel, public AbstractSubscribableChannel brokerChannel(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel, TaskExecutor brokerChannelExecutor) { AbstractSubscribableChannel clientOutboundChannel, Executor brokerChannelExecutor) {
// synchronous // synchronous
return new ExecutorSubscribableChannel(null); return new ExecutorSubscribableChannel(null);
} }

View File

@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -29,7 +30,6 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.TaskExecutor;
import org.springframework.messaging.Message; import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.handler.annotation.MessageMapping; import org.springframework.messaging.handler.annotation.MessageMapping;
@ -318,7 +318,7 @@ class WebSocketMessageBrokerConfigurationSupportTests {
@Override @Override
@Bean @Bean
public AbstractSubscribableChannel clientInboundChannel(TaskExecutor clientInboundChannelExecutor) { public AbstractSubscribableChannel clientInboundChannel(Executor clientInboundChannelExecutor) {
TestChannel channel = new TestChannel(); TestChannel channel = new TestChannel();
channel.setInterceptors(super.clientInboundChannel(clientInboundChannelExecutor).getInterceptors()); channel.setInterceptors(super.clientInboundChannel(clientInboundChannelExecutor).getInterceptors());
return channel; return channel;
@ -326,7 +326,7 @@ class WebSocketMessageBrokerConfigurationSupportTests {
@Override @Override
@Bean @Bean
public AbstractSubscribableChannel clientOutboundChannel(TaskExecutor clientOutboundChannelExecutor) { public AbstractSubscribableChannel clientOutboundChannel(Executor clientOutboundChannelExecutor) {
TestChannel channel = new TestChannel(); TestChannel channel = new TestChannel();
channel.setInterceptors(super.clientOutboundChannel(clientOutboundChannelExecutor).getInterceptors()); channel.setInterceptors(super.clientOutboundChannel(clientOutboundChannelExecutor).getInterceptors());
return channel; return channel;
@ -334,7 +334,7 @@ class WebSocketMessageBrokerConfigurationSupportTests {
@Override @Override
public AbstractSubscribableChannel brokerChannel(AbstractSubscribableChannel clientInboundChannel, public AbstractSubscribableChannel brokerChannel(AbstractSubscribableChannel clientInboundChannel,
AbstractSubscribableChannel clientOutboundChannel, TaskExecutor brokerChannelExecutor) { AbstractSubscribableChannel clientOutboundChannel, Executor brokerChannelExecutor) {
TestChannel channel = new TestChannel(); TestChannel channel = new TestChannel();
channel.setInterceptors(super.brokerChannel(clientInboundChannel, clientOutboundChannel, brokerChannelExecutor).getInterceptors()); channel.setInterceptors(super.brokerChannel(clientInboundChannel, clientOutboundChannel, brokerChannelExecutor).getInterceptors());
return channel; return channel;