Spring Cloud Managed Thread Pools Are Automatically Wrapped with Trace Information to Preserve Context
This article explains how Spring Cloud automatically wraps container‑managed thread pool beans with tracing proxies to preserve distributed‑trace information, details the ExecutorBeanPostProcessor implementation, shows the relevant code for detecting and instrumenting executors, and notes when manual wrapping is required.
Spring Cloud container‑managed thread pool instances are automatically wrapped with tracing proxies so that distributed‑trace (link) information is retained across asynchronous executions.
The core of this functionality is the
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SleuthAsyncProperties.class)
@ConditionalOnProperty(value = "spring.sleuth.async.enabled", matchIfMissing = true)
@ConditionalOnBean(Tracer.class)
@AutoConfigureAfter(BraveAutoConfiguration.class)
public class TraceAsyncDefaultAutoConfiguration {
@Bean
@ConditionalOnProperty(value = "spring.sleuth.scheduled.enabled", matchIfMissing = true)
static ExecutorBeanPostProcessor executorBeanPostProcessor(BeanFactory beanFactory) {
return new ExecutorBeanPostProcessor(beanFactory);
}
}implements BeanPostProcessor and intercepts bean creation.
In postProcessAfterInitialization, the processor checks whether the bean is an Executor and not already a tracing wrapper. The check is performed by ExecutorInstrumentor.isApplicableForInstrumentation:
public static boolean isApplicableForInstrumentation(Object bean) {
return bean instanceof Executor && !(bean instanceof LazyTraceThreadPoolTaskExecutor
|| bean instanceof TraceableScheduledExecutorService || bean instanceof TraceableExecutorService
|| bean instanceof LazyTraceAsyncTaskExecutor || bean instanceof LazyTraceExecutor);
}If the bean qualifies, the instrument method of ExecutorInstrumentor creates a proxy appropriate to the concrete executor type:
public Object instrument(Object bean, String beanName) {
if (!isApplicableForInstrumentation(bean)) {
log.info("Bean is already instrumented or is not applicable for instrumentation " + beanName);
return bean;
}
if (bean instanceof ThreadPoolTaskExecutor) {
if (isProxyNeeded(beanName)) {
return wrapThreadPoolTaskExecutor(bean, beanName);
} else {
log.info("Not instrumenting bean " + beanName);
}
} else if (bean instanceof ScheduledExecutorService) {
if (isProxyNeeded(beanName)) {
return wrapScheduledExecutorService(bean, beanName);
} else {
log.info("Not instrumenting bean " + beanName);
}
} else if (bean instanceof ExecutorService) {
if (isProxyNeeded(beanName)) {
return wrapExecutorService(bean, beanName);
} else {
log.info("Not instrumenting bean " + beanName);
}
} else if (bean instanceof AsyncTaskExecutor) {
if (isProxyNeeded(beanName)) {
return wrapAsyncTaskExecutor(bean, beanName);
} else {
log.info("Not instrumenting bean " + beanName);
}
} else if (bean instanceof Executor) {
return wrapExecutor(bean, beanName);
}
return bean;
}
private Object wrapExecutor(Object bean, String beanName) {
Executor executor = (Executor) bean;
boolean methodFinal = anyFinalMethods(executor);
boolean classFinal = Modifier.isFinal(bean.getClass().getModifiers());
boolean cglibProxy = !methodFinal && !classFinal;
try {
return createProxy(bean, cglibProxy, new ExecutorMethodInterceptor<>(executor, this.beanFactory, beanName));
} catch (AopConfigException ex) {
if (cglibProxy) {
if (log.isDebugEnabled()) {
log.debug("Exception occurred while trying to create a proxy, falling back to JDK proxy", ex);
}
return createProxy(bean, false, new ExecutorMethodInterceptor<>(executor, this.beanFactory, beanName));
}
throw ex;
}
}The proxy creation respects whether the original executor class is final; if it is, a byte‑code (CGLIB) proxy is used, otherwise a JDK dynamic proxy may be applied.
The implementation comes from the spring-cloud-sleuth-autoconfigure module version 3.1.1. For thread pools that are manually instantiated (e.g., via new or not declared as Spring beans), developers must explicitly wrap them with a tracing executor to retain link information.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Cognitive Technology Team
Cognitive Technology Team regularly delivers the latest IT news, original content, programming tutorials and experience sharing, with daily perks awaiting you.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
