Spring Boot自定义@Async Wrap Callable

时间:2016-05-25 13:03:56

标签: spring asynchronous spring-boot spring-aop

我正在开发支持多租户的应用程序。租户的unqiue标识符存储在本地线程中,可以通过某些服务访问。 为了允许并行处理,我创建了一个Callable包装器,设置了线程局部变量:

class TenantAwareCallable<T> implements Callable<T> {
  private final String tenantName;
  private final Callable<T> delegate;

  TenantAwareCallable(Callable<T> delegate, String tenantName) {
    this.delegate = delegate;
    this.tenantName = tenantName;
  }

  @Override
  public T call() throws Exception {
    // set threadlocal
    TenantContext.setCurrentTenantName(tenantName);

    try {
      return delegate.call();
    } catch (Exception e) {
     // log and handle
    } finally {
     TenantContext.clear();
    }
  }
}

这已经可以在应用程序中使用。但我想要的是一些自定义@Async注释,例如@TenantAwareAsync@TenantPreservingAsync,它包装了Spring在这一个中创建的callable,然后执行它。

有没有办法开始这个?

提前致谢!

1 个答案:

答案 0 :(得分:0)

我有一个有效的解决方案,所以我认为在这里分享可能会对某些人有所帮助。

我解决了这个问题,不是使用TenantAwareCallable,而是通过自定义Executor服务。我选择扩展Spring的ThreadPoolTask​​Scheduler(因为这是我们在项目中使用的)。

public class ContextAwareThreadPoolTaskScheduler extends ThreadPoolTaskScheduler {
  @Override
  protected ScheduledExecutorService createExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
    return new ContextAwareThreadPoolTaskExecutor(poolSize, threadFactory, rejectedExecutionHandler);
  }
}

上下文数据的实际设置是在自定义ScheduledThreadPoolExecutor

中完成的
public class ContextAwareThreadPoolTaskExecutor extends ScheduledThreadPoolExecutor {

  public ContextAwareThreadPoolTaskExecutor(int poolSize, ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
    super(poolSize, threadFactory, rejectedExecutionHandler);
  }

  @Override
  protected <V> RunnableScheduledFuture<V> decorateTask(Callable<V> callable, RunnableScheduledFuture<V> task) {
    return new ContextAwareTask<V>(task);
  }

  @Override
  protected <V> RunnableScheduledFuture<V> decorateTask(Runnable runnable, RunnableScheduledFuture<V> task) {
    return new ContextAwareTask<V>(task);
  }

  static private class ContextAwareTask<T> implements RunnableScheduledFuture<T> {

    private final RunnableScheduledFuture<T> delegate;

    private final TenantContextHolder multitenantContextHolder;
    private final LoggingContextHolder loggingContextHolder;
    private final SecurityContext securityContext;

    ContextAwareTask(RunnableScheduledFuture<T> delegate) {
      this.delegate = delegate;

      multitenantContextHolder = TenantContextHolder.newInstance();
      loggingContextHolder = LoggingContextHolder.newInstance();
      securityContext = SecurityContextHolder.getContext();
    }

    @Override
    public void run() {
      multitenantContextHolder.apply();
      loggingContextHolder.apply();
      SecurityContextHolder.setContext(securityContext);

      delegate.run();

      SecurityContextHolder.clearContext();
      loggingContextHolder.clear();
      multitenantContextHolder.clear();
    }

    // all other methods are just delegates
  }
}

持有者基本上只是存储上下文状态的对象,并将其应用于新线程。

public class TenantContextHolder {

  private String tenantName;

  public static TenantContextHolder newInstance() {
    return new TenantContextHolder();
  }

  private TenantContextHolder() {
    this.tenantName = TenantContext.getCurrentTenantName();
  }

  public void apply() {
    TenantContext.setCurrentTenantName(tenantName);
  }

  public void clear() {
    TenantContext.clear();
  }
}

然后可以在Spring环境中配置Scheduler的自定义实现。

@Configuration
public class AsyncConfiguration implements AsyncConfigurer {
  private ThreadPoolTaskScheduler taskScheduler;

  @Bean
  public ThreadPoolTaskScheduler taskScheduler() {
    if (taskScheduler == null) {
      taskScheduler = new ContextAwareThreadPoolTaskScheduler();
    }
    return taskScheduler;
  }

  @Override
  public Executor getAsyncExecutor() {
    return taskScheduler();
  }
}