Caches executor wrappers (#2033)
without this change whenever a traced executor is created (either via a proxy or directly) we create a new instance of that traced wrapper. The problem with that is such that we create a lot of objects (e.g. each getExecutor() would return a new instance of the traced version). There are projects such as Micrometer that create WeakReferences to those objects. That means that if we don't cache the traced instance then we will lose the WeakReference upon the first GC. with this change we're introducing new static wrapper methods that cache the traced instance for a given delegate. That means that not only will we create fewer objects but also we will honour the WeakReference mechanisms. fixes gh-2020
This commit is contained in:
committed by
GitHub
parent
565d00c73a
commit
d19b72d553
@@ -92,7 +92,7 @@ public class TraceAsyncDefaultAutoConfiguration {
|
||||
@Override
|
||||
public Executor getAsyncExecutor() {
|
||||
Executor delegate = getDefaultExecutor();
|
||||
return new LazyTraceExecutor(this.beanFactory, delegate);
|
||||
return LazyTraceExecutor.wrap(this.beanFactory, delegate);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,10 +20,13 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
@@ -176,43 +179,43 @@ public class ExecutorInstrumentor {
|
||||
Object createThreadPoolTaskExecutorProxy(Object bean, boolean cglibProxy, ThreadPoolTaskExecutor executor,
|
||||
String beanName) {
|
||||
if (!cglibProxy) {
|
||||
return new LazyTraceThreadPoolTaskExecutor(this.beanFactory, executor, beanName);
|
||||
return LazyTraceThreadPoolTaskExecutor.wrap(this.beanFactory, executor, beanName);
|
||||
}
|
||||
return getProxiedObject(bean, beanName, true, executor,
|
||||
() -> new LazyTraceThreadPoolTaskExecutor(this.beanFactory, executor, beanName));
|
||||
() -> LazyTraceThreadPoolTaskExecutor.wrap(this.beanFactory, executor, beanName));
|
||||
}
|
||||
|
||||
Supplier<Executor> createThreadPoolTaskSchedulerProxy(ThreadPoolTaskScheduler executor, String beanName) {
|
||||
return () -> new LazyTraceThreadPoolTaskScheduler(this.beanFactory, executor, beanName);
|
||||
return () -> LazyTraceThreadPoolTaskScheduler.wrap(this.beanFactory, executor, beanName);
|
||||
}
|
||||
|
||||
Supplier<Executor> createScheduledThreadPoolExecutorProxy(ScheduledThreadPoolExecutor executor, String beanName) {
|
||||
return () -> new LazyTraceScheduledThreadPoolExecutor(executor.getCorePoolSize(), executor.getThreadFactory(),
|
||||
return () -> LazyTraceScheduledThreadPoolExecutor.wrap(executor.getCorePoolSize(), executor.getThreadFactory(),
|
||||
executor.getRejectedExecutionHandler(), this.beanFactory, executor, beanName);
|
||||
}
|
||||
|
||||
Object createExecutorServiceProxy(Object bean, boolean cglibProxy, ExecutorService executor, String beanName) {
|
||||
return getProxiedObject(bean, beanName, cglibProxy, executor, () -> {
|
||||
if (executor instanceof ScheduledExecutorService) {
|
||||
return new TraceableScheduledExecutorService(this.beanFactory, executor, beanName);
|
||||
return TraceableScheduledExecutorService.wrap(this.beanFactory, executor, beanName);
|
||||
}
|
||||
return new TraceableExecutorService(this.beanFactory, executor, beanName);
|
||||
return TraceableExecutorService.wrap(this.beanFactory, executor, beanName);
|
||||
});
|
||||
}
|
||||
|
||||
Object createScheduledExecutorServiceProxy(Object bean, boolean cglibProxy, ScheduledExecutorService executor,
|
||||
String beanName) {
|
||||
return getProxiedObject(bean, beanName, cglibProxy, executor,
|
||||
() -> new TraceableScheduledExecutorService(this.beanFactory, executor, beanName));
|
||||
() -> TraceableScheduledExecutorService.wrap(this.beanFactory, executor, beanName));
|
||||
}
|
||||
|
||||
Object createAsyncTaskExecutorProxy(Object bean, boolean cglibProxy, AsyncTaskExecutor executor, String beanName) {
|
||||
return getProxiedObject(bean, beanName, cglibProxy, executor, () -> {
|
||||
if (bean instanceof ThreadPoolTaskScheduler) {
|
||||
return new LazyTraceThreadPoolTaskScheduler(this.beanFactory, (ThreadPoolTaskScheduler) executor,
|
||||
return LazyTraceThreadPoolTaskScheduler.wrap(this.beanFactory, (ThreadPoolTaskScheduler) executor,
|
||||
beanName);
|
||||
}
|
||||
return new LazyTraceAsyncTaskExecutor(this.beanFactory, executor, beanName);
|
||||
return LazyTraceAsyncTaskExecutor.wrap(this.beanFactory, executor, beanName);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -259,7 +262,7 @@ public class ExecutorInstrumentor {
|
||||
factory.addAdvice(new ExecutorMethodInterceptor<Executor>(executor, this.beanFactory, beanName) {
|
||||
@Override
|
||||
Executor executor(BeanFactory beanFactory, Executor executor, String beanName) {
|
||||
return supplier.get();
|
||||
return executorFromCache(beanFactory, executor, beanName, e -> supplier.get());
|
||||
}
|
||||
});
|
||||
factory.setTarget(bean);
|
||||
@@ -316,6 +319,8 @@ class ExecutorMethodInterceptor<T extends Executor> implements MethodInterceptor
|
||||
|
||||
private final String beanName;
|
||||
|
||||
private static final Map<Executor, Executor> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
ExecutorMethodInterceptor(T delegate, BeanFactory beanFactory, String beanName) {
|
||||
this.delegate = delegate;
|
||||
this.beanFactory = beanFactory;
|
||||
@@ -344,8 +349,15 @@ class ExecutorMethodInterceptor<T extends Executor> implements MethodInterceptor
|
||||
return ReflectionUtils.findMethod(object.getClass(), method.getName(), method.getParameterTypes());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T executor(BeanFactory beanFactory, T executor, String beanName) {
|
||||
return (T) new LazyTraceExecutor(beanFactory, executor, beanName);
|
||||
return executorFromCache(beanFactory, executor, beanName,
|
||||
e -> (T) LazyTraceExecutor.wrap(beanFactory, e, beanName));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T executorFromCache(BeanFactory beanFactory, T executor, String beanName, Function<Executor, Executor> function) {
|
||||
return (T) CACHE.computeIfAbsent(executor, function);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public class LazyTraceAsyncCustomizer extends AsyncConfigurerSupport {
|
||||
if (this.delegate.getAsyncExecutor() instanceof LazyTraceExecutor) {
|
||||
return this.delegate.getAsyncExecutor();
|
||||
}
|
||||
return new LazyTraceExecutor(this.beanFactory, this.delegate.getAsyncExecutor());
|
||||
return LazyTraceExecutor.wrap(this.beanFactory, this.delegate.getAsyncExecutor());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.async;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -29,6 +31,7 @@ import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.internal.ContextUtil;
|
||||
import org.springframework.cloud.sleuth.internal.DefaultSpanNamer;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* {@link AsyncTaskExecutor} that wraps {@link Runnable} and {@link Callable} in a trace
|
||||
@@ -40,6 +43,8 @@ import org.springframework.core.task.AsyncTaskExecutor;
|
||||
// public as most types in this package were documented for use
|
||||
public class LazyTraceAsyncTaskExecutor implements AsyncTaskExecutor {
|
||||
|
||||
private static final Map<AsyncTaskExecutor, LazyTraceAsyncTaskExecutor> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Log log = LogFactory.getLog(LazyTraceAsyncTaskExecutor.class);
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
@@ -64,6 +69,28 @@ public class LazyTraceAsyncTaskExecutor implements AsyncTaskExecutor {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Executor in a trace instance.
|
||||
* @param beanFactory bean factory
|
||||
* @param delegate delegate to wrap
|
||||
* @param beanName bean name
|
||||
* @return traced instance
|
||||
*/
|
||||
public static LazyTraceAsyncTaskExecutor wrap(BeanFactory beanFactory, @NonNull AsyncTaskExecutor delegate,
|
||||
String beanName) {
|
||||
return CACHE.computeIfAbsent(delegate, e -> new LazyTraceAsyncTaskExecutor(beanFactory, delegate, beanName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Executor in a trace instance.
|
||||
* @param beanFactory bean factory
|
||||
* @param delegate delegate to wrap
|
||||
* @return traced instance
|
||||
*/
|
||||
public static LazyTraceAsyncTaskExecutor wrap(BeanFactory beanFactory, @NonNull AsyncTaskExecutor delegate) {
|
||||
return CACHE.computeIfAbsent(delegate, e -> new LazyTraceAsyncTaskExecutor(beanFactory, delegate, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task) {
|
||||
Runnable taskToRun = task;
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.async;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -27,6 +29,7 @@ import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.internal.ContextUtil;
|
||||
import org.springframework.cloud.sleuth.internal.DefaultSpanNamer;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* {@link Executor} that wraps {@link Runnable} in a trace representation.
|
||||
@@ -39,6 +42,8 @@ public class LazyTraceExecutor implements Executor {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LazyTraceExecutor.class);
|
||||
|
||||
private static final Map<Executor, LazyTraceExecutor> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private final Executor delegate;
|
||||
@@ -61,6 +66,27 @@ public class LazyTraceExecutor implements Executor {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Executor in a trace instance.
|
||||
* @param beanFactory bean factory
|
||||
* @param delegate delegate to wrap
|
||||
* @param beanName bean name
|
||||
* @return traced instance
|
||||
*/
|
||||
public static LazyTraceExecutor wrap(BeanFactory beanFactory, @NonNull Executor delegate, String beanName) {
|
||||
return CACHE.computeIfAbsent(delegate, e -> new LazyTraceExecutor(beanFactory, delegate, beanName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Executor in a trace instance.
|
||||
* @param beanFactory bean factory
|
||||
* @param delegate delegate to wrap
|
||||
* @return traced instance
|
||||
*/
|
||||
public static LazyTraceExecutor wrap(BeanFactory beanFactory, @NonNull Executor delegate) {
|
||||
return CACHE.computeIfAbsent(delegate, e -> new LazyTraceExecutor(beanFactory, delegate, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
if (ContextUtil.isContextUnusable(this.beanFactory)) {
|
||||
|
||||
@@ -20,8 +20,10 @@ import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
@@ -42,6 +44,7 @@ import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.internal.ContextUtil;
|
||||
import org.springframework.cloud.sleuth.internal.DefaultSpanNamer;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -56,6 +59,8 @@ class LazyTraceScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LazyTraceScheduledThreadPoolExecutor.class);
|
||||
|
||||
private static final Map<ScheduledThreadPoolExecutor, LazyTraceScheduledThreadPoolExecutor> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private final ScheduledThreadPoolExecutor delegate;
|
||||
@@ -175,6 +180,19 @@ class LazyTraceScheduledThreadPoolExecutor extends ScheduledThreadPoolExecutor {
|
||||
this.newTaskForCallable = makeAccessibleIfNotNullAndOverridden(newTaskForCallable);
|
||||
}
|
||||
|
||||
static LazyTraceScheduledThreadPoolExecutor wrap(int corePoolSize, BeanFactory beanFactory,
|
||||
@NonNull ScheduledThreadPoolExecutor delegate, String beanName) {
|
||||
return CACHE.computeIfAbsent(delegate,
|
||||
e -> new LazyTraceScheduledThreadPoolExecutor(corePoolSize, beanFactory, delegate, beanName));
|
||||
}
|
||||
|
||||
static LazyTraceScheduledThreadPoolExecutor wrap(int corePoolSize, ThreadFactory threadFactory,
|
||||
RejectedExecutionHandler handler, BeanFactory beanFactory, @NonNull ScheduledThreadPoolExecutor delegate,
|
||||
String beanName) {
|
||||
return CACHE.computeIfAbsent(delegate, e -> new LazyTraceScheduledThreadPoolExecutor(corePoolSize,
|
||||
threadFactory, handler, beanFactory, delegate, beanName));
|
||||
}
|
||||
|
||||
private Runnable traceRunnableWhenContextReady(Runnable delegate) {
|
||||
if (isContextUnusable()) {
|
||||
return delegate;
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.async;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
@@ -32,6 +34,7 @@ import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.internal.ContextUtil;
|
||||
import org.springframework.cloud.sleuth.internal.DefaultSpanNamer;
|
||||
import org.springframework.core.task.TaskDecorator;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
|
||||
@@ -46,6 +49,8 @@ public class LazyTraceThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LazyTraceThreadPoolTaskExecutor.class);
|
||||
|
||||
private static final Map<ThreadPoolTaskExecutor, LazyTraceThreadPoolTaskExecutor> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private final ThreadPoolTaskExecutor delegate;
|
||||
@@ -68,6 +73,30 @@ public class LazyTraceThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Executor in a trace instance.
|
||||
* @param beanFactory bean factory
|
||||
* @param delegate delegate to wrap
|
||||
* @param beanName bean name
|
||||
* @return traced instance
|
||||
*/
|
||||
public static LazyTraceThreadPoolTaskExecutor wrap(BeanFactory beanFactory,
|
||||
@NonNull ThreadPoolTaskExecutor delegate, String beanName) {
|
||||
return CACHE.computeIfAbsent(delegate,
|
||||
e -> new LazyTraceThreadPoolTaskExecutor(beanFactory, delegate, beanName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Executor in a trace instance.
|
||||
* @param beanFactory bean factory
|
||||
* @param delegate delegate to wrap
|
||||
* @return traced instance
|
||||
*/
|
||||
public static LazyTraceThreadPoolTaskExecutor wrap(BeanFactory beanFactory,
|
||||
@NonNull ThreadPoolTaskExecutor delegate) {
|
||||
return CACHE.computeIfAbsent(delegate, e -> new LazyTraceThreadPoolTaskExecutor(beanFactory, delegate, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable task) {
|
||||
this.delegate.execute(wrap(task));
|
||||
|
||||
@@ -20,7 +20,9 @@ import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
@@ -39,6 +41,7 @@ import org.springframework.cloud.sleuth.SpanNamer;
|
||||
import org.springframework.cloud.sleuth.Tracer;
|
||||
import org.springframework.cloud.sleuth.internal.ContextUtil;
|
||||
import org.springframework.cloud.sleuth.internal.DefaultSpanNamer;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.scheduling.Trigger;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
@@ -59,6 +62,8 @@ class LazyTraceThreadPoolTaskScheduler extends ThreadPoolTaskScheduler {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LazyTraceThreadPoolTaskScheduler.class);
|
||||
|
||||
private static final Map<ThreadPoolTaskScheduler, LazyTraceThreadPoolTaskScheduler> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private final BeanFactory beanFactory;
|
||||
|
||||
private final ThreadPoolTaskScheduler delegate;
|
||||
@@ -97,6 +102,19 @@ class LazyTraceThreadPoolTaskScheduler extends ThreadPoolTaskScheduler {
|
||||
makeAccessibleIfNotNull(this.getDefaultThreadNamePrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Executor in a trace instance.
|
||||
* @param beanFactory bean factory
|
||||
* @param delegate delegate to wrap
|
||||
* @param beanName bean name
|
||||
* @return traced instance
|
||||
*/
|
||||
static LazyTraceThreadPoolTaskScheduler wrap(BeanFactory beanFactory, @NonNull ThreadPoolTaskScheduler delegate,
|
||||
String beanName) {
|
||||
return CACHE.computeIfAbsent(delegate,
|
||||
e -> new LazyTraceThreadPoolTaskScheduler(beanFactory, delegate, beanName));
|
||||
}
|
||||
|
||||
private void makeAccessibleIfNotNull(Method method) {
|
||||
if (method != null) {
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
@@ -147,7 +165,7 @@ class LazyTraceThreadPoolTaskScheduler extends ThreadPoolTaskScheduler {
|
||||
if (executorService instanceof TraceableScheduledExecutorService) {
|
||||
return executorService;
|
||||
}
|
||||
return new TraceableExecutorService(this.beanFactory, executorService, this.beanName);
|
||||
return TraceableExecutorService.wrap(this.beanFactory, executorService, this.beanName);
|
||||
}
|
||||
|
||||
private RejectedExecutionHandler traceRejectedExecutionHandler(RejectedExecutionHandler rejectedExecutionHandler) {
|
||||
@@ -172,14 +190,14 @@ class LazyTraceThreadPoolTaskScheduler extends ThreadPoolTaskScheduler {
|
||||
if (executorService instanceof TraceableScheduledExecutorService) {
|
||||
return executorService;
|
||||
}
|
||||
return new TraceableScheduledExecutorService(this.beanFactory, executorService, this.beanName);
|
||||
return TraceableScheduledExecutorService.wrap(this.beanFactory, executorService, this.beanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledExecutorService getScheduledExecutor() throws IllegalStateException {
|
||||
ScheduledExecutorService executor = this.delegate.getScheduledExecutor();
|
||||
return executor instanceof TraceableScheduledExecutorService ? executor
|
||||
: new TraceableScheduledExecutorService(this.beanFactory, executor, this.beanName);
|
||||
: TraceableScheduledExecutorService.wrap(this.beanFactory, executor, this.beanName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -188,7 +206,7 @@ class LazyTraceThreadPoolTaskScheduler extends ThreadPoolTaskScheduler {
|
||||
if (executor instanceof LazyTraceScheduledThreadPoolExecutor) {
|
||||
return executor;
|
||||
}
|
||||
return new LazyTraceScheduledThreadPoolExecutor(executor.getCorePoolSize(), executor.getThreadFactory(),
|
||||
return LazyTraceScheduledThreadPoolExecutor.wrap(executor.getCorePoolSize(), executor.getThreadFactory(),
|
||||
executor.getRejectedExecutionHandler(), this.beanFactory, executor, this.beanName);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ package org.springframework.cloud.sleuth.instrument.async;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
@@ -40,6 +42,8 @@ import org.springframework.cloud.sleuth.internal.ContextUtil;
|
||||
// public as most types in this package were documented for use
|
||||
public class TraceableExecutorService implements ExecutorService {
|
||||
|
||||
private static final Map<ExecutorService, TraceableExecutorService> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
final ExecutorService delegate;
|
||||
|
||||
final String spanName;
|
||||
@@ -60,6 +64,27 @@ public class TraceableExecutorService implements ExecutorService {
|
||||
this.spanName = spanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Executor in a trace instance.
|
||||
* @param beanFactory bean factory
|
||||
* @param delegate delegate to wrap
|
||||
* @param beanName bean name
|
||||
* @return traced instance
|
||||
*/
|
||||
public static TraceableExecutorService wrap(BeanFactory beanFactory, ExecutorService delegate, String beanName) {
|
||||
return CACHE.computeIfAbsent(delegate, e -> new TraceableExecutorService(beanFactory, delegate, beanName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Executor in a trace instance.
|
||||
* @param beanFactory bean factory
|
||||
* @param delegate delegate to wrap
|
||||
* @return traced instance
|
||||
*/
|
||||
public static TraceableExecutorService wrap(BeanFactory beanFactory, ExecutorService delegate) {
|
||||
return CACHE.computeIfAbsent(delegate, e -> new TraceableExecutorService(beanFactory, delegate, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
this.delegate.execute(ContextUtil.isContextUnusable(this.beanFactory) ? command
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package org.springframework.cloud.sleuth.instrument.async;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
@@ -34,6 +36,8 @@ import org.springframework.cloud.sleuth.internal.ContextUtil;
|
||||
// public as most types in this package were documented for use
|
||||
public class TraceableScheduledExecutorService extends TraceableExecutorService implements ScheduledExecutorService {
|
||||
|
||||
private static final Map<ExecutorService, TraceableScheduledExecutorService> CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
public TraceableScheduledExecutorService(BeanFactory beanFactory, final ExecutorService delegate) {
|
||||
super(beanFactory, delegate);
|
||||
}
|
||||
@@ -42,6 +46,29 @@ public class TraceableScheduledExecutorService extends TraceableExecutorService
|
||||
super(beanFactory, delegate, beanName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Executor in a trace instance.
|
||||
* @param beanFactory bean factory
|
||||
* @param delegate delegate to wrap
|
||||
* @param beanName bean name
|
||||
* @return traced instance
|
||||
*/
|
||||
public static TraceableScheduledExecutorService wrap(BeanFactory beanFactory, ExecutorService delegate,
|
||||
String beanName) {
|
||||
return CACHE.computeIfAbsent(delegate,
|
||||
e -> new TraceableScheduledExecutorService(beanFactory, delegate, beanName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps the Executor in a trace instance.
|
||||
* @param beanFactory bean factory
|
||||
* @param delegate delegate to wrap
|
||||
* @return traced instance
|
||||
*/
|
||||
public static TraceableScheduledExecutorService wrap(BeanFactory beanFactory, ExecutorService delegate) {
|
||||
return CACHE.computeIfAbsent(delegate, e -> new TraceableScheduledExecutorService(beanFactory, delegate, null));
|
||||
}
|
||||
|
||||
private ScheduledExecutorService getScheduledExecutorService() {
|
||||
return (ScheduledExecutorService) this.delegate;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,12 @@
|
||||
package org.springframework.cloud.sleuth.instrument.async;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.assertj.core.api.BDDAssertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.BDDMockito;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
@@ -45,6 +47,8 @@ public class LazyTraceAsyncCustomizerTest {
|
||||
|
||||
@Test
|
||||
public void should_wrap_async_executor_in_trace_version() throws Exception {
|
||||
BDDMockito.given(this.asyncConfigurer.getAsyncExecutor()).willReturn(Executors.newSingleThreadExecutor());
|
||||
|
||||
Executor executor = this.lazyTraceAsyncCustomizer.getAsyncExecutor();
|
||||
|
||||
BDDAssertions.then(executor).isExactlyInstanceOf(LazyTraceExecutor.class);
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.RejectedExecutionHandler;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
@@ -94,6 +95,8 @@ public abstract class LazyTraceThreadPoolTaskSchedulerTests implements TestTraci
|
||||
|
||||
@Test
|
||||
public void getScheduledExecutor() {
|
||||
BDDMockito.given(this.delegate.getScheduledExecutor()).willReturn(Executors.newScheduledThreadPool(1));
|
||||
|
||||
this.executor.getScheduledExecutor();
|
||||
|
||||
BDDMockito.then(this.delegate).should().getScheduledExecutor();
|
||||
|
||||
Reference in New Issue
Block a user