2016-05-25 6 views
1

私はマルチテナントをサポートするアプリケーションを開発中です。テナントのユニーク識別子はローカルのスレッドに格納され、何らかのサービスを介してアクセスできます。 Iは、呼び出し可能ラッパーを作成したスレッドローカル変数を設定した、並列処理を可能にする:スプリングブートカスタム@Async Wrap呼び出し可能

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(); 
    } 
    } 
} 

これはすでにアプリケーションに使用することができます。しかし、私が望むものは、注釈(例:@TenantAwareAsyncまたは@TenantPreservingAsync)です。これはSpringで作成された呼び出し可能ファイルをこのファイルにラップして実行します。

これを開始する方法はありますか?

ありがとうございます!

答えて

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環境で構成できます。

@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(); 
    } 
} 
関連する問題