-
Couldn't load subscription status.
- Fork 38.8k
Description
TaskDecorator doesn't directly work with task scheduler implementations - ThreadPoolTaskScheduler/ConcurrentTaskScheduler.
Related: #18502
I think the underlying reason is there is no easy way of applying TaskDecorator to ScheduledExecutorService.
Currently, I workaround by wrapping ScheduledExecutorService with a proxy that performs task decoration.
Proxy Handler:
public class TaskDecoratingScheduledExecutorServiceInterceptor implements MethodInterceptor {
private final TaskDecorator taskDecorator;
public TaskDecoratingScheduledExecutorServiceInterceptor(TaskDecorator taskDecorator) {
this.taskDecorator = taskDecorator;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object[] args = invocation.getArguments();
if (args.length == 0) {
return invocation.proceed(); // no decoration, simply proceed
}
Object swapped;
if (args[0] instanceof Runnable) {
swapped = replaceRunnable(method, (Runnable) args[0]);
} else if (args[0] instanceof Callable) {
swapped = replaceCallable(method, (Callable) args[0]);
} else if (args[0] instanceof Collection) { // see the ExecutorService API
swapped = ((Collection<? extends Callable<?>>) args[0]).stream()
.map(callable -> replaceCallable(method, callable))
.collect(toList());
} else {
return invocation.proceed(); // bail out, no replace needed
}
args[0] = swapped; // swap
return invocation.proceed();
}
....
}Wrap created ScheduledThreadPoolExecutor in ThreadPoolTaskScheduler:
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler() {
private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor;
@Override
protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
// keep it for "getScheduledThreadPoolExecutor()"
this.scheduledThreadPoolExecutor = (ScheduledThreadPoolExecutor) super.createExecutor(poolSize, threadFactory, rejectedExecutionHandler);
ScheduledExecutorService executorService = this.scheduledThreadPoolExecutor;
// apply task decorator via proxy
ProxyFactory proxyFactory = new ProxyFactory(executorService);
proxyFactory.addAdvice(new TaskDecoratingScheduledExecutorServiceInterceptor(taskDecorator));
return (ScheduledExecutorService) proxyFactory.getProxy();
}
@Override
public ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor() throws IllegalStateException {
return this.scheduledThreadPoolExecutor;
}
}I think it would be nice that ThreadPoolTaskScheduler/ConcurrentTaskScheduler to have some API to work with TaskDecorator OR a way to easily customize underlying ScheduledExecutorService to apply decorators.
For example, a delegate class that takes TaskDecorator:
public class TaskDecoratingScheduledExecutorServiceDelegate implement ScheduledExecutorService {
private final ScheduledExecutorService delegate;
private final TaskDecorator taskDecorator;
...
}