java - Spring @async 子线程上下文 Multi-Tenancy

标签 java spring multithreading asynchronous multi-tenant

我有一个应用程序可以向我的 Java 应用程序发送一些 REST 调用。我必须在 @Async 模式下运行最后一个命令,这样用户可以在异步任务执行另一个 SOAP 调用时继续使用该应用程序。

问题是我在数据库中自动连接了 TenantContext 和几个租户标识符。在执行异步任务时,它具有我的主线程的租户上下文,并为错误的租户保存数据。

这是我的 JpaTransactionManager,它会为数据库中的每个事务调用:

@Autowired
private TenantContext tenantContext;

@Autowired
private Flyway flyway;

@Autowired
private Environment environment;

@Override
protected void doBegin(final Object transaction, final TransactionDefinition definition)
{
    super.doBegin(transaction, definition);
    final EntityManagerHolder entityManagerHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(getEntityManagerFactory());
    final EntityManager entityManager = entityManagerHolder.getEntityManager();

    String subAccountId = "";
    if (environment.getActiveProfiles().length == 0 || !environment.getActiveProfiles()[0].equals("production"))
    {
        subAccountId = "SCAN4CLOUD";
    } else
    {
        subAccountId = tenantContext.getTenant().getAccount().getId().toUpperCase();
    }

    entityManager.setProperty("tenant", subAccountId);
}

我已尝试使用以下类拦截异步调用以设置正确的租户上下文。

@Configuration
@EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport
{
@Autowired
private TenantContext tenantContext;

@Autowired
private Environment environment;

private HashMap<String, ContextAwarePoolExecutor> tenantThreadPoolTaskExecutor = new HashMap<String, ContextAwarePoolExecutor>();

@Override
@Bean
@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Executor getAsyncExecutor()
{

    String subAccountId = "";

    if (environment.getActiveProfiles().length == 0 || !environment.getActiveProfiles()[0].equals("production"))
    {
        subAccountId = "SCAN4CLOUD";
    } else
    {
        subAccountId = tenantContext.getTenant().getAccount().getId().toUpperCase();
    }

    if (!tenantThreadPoolTaskExecutor.containsKey(subAccountId))
    {
        tenantThreadPoolTaskExecutor.put(subAccountId, new ContextAwarePoolExecutor(tenantContext));
    }

    return tenantThreadPoolTaskExecutor.get(subAccountId);
}

上下文感知池执行器:

public class ContextAwarePoolExecutor extends ThreadPoolTaskExecutor
{
    private TenantContext tenantContext;

    public ContextAwarePoolExecutor(TenantContext tenantContext)
    {
        this.tenantContext = tenantContext;
    }

    @Override
    public <T> Future<T> submit(Callable<T> task)
    {
        return super.submit(new ContextAwareCallable(task, tenantContext));
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task)
    {
        return super.submitListenable(new ContextAwareCallable(task, tenantContext));
    }
}

上下文感知调用:

public class ContextAwareCallable<T> implements Callable<T>
{
private Callable<T> task;
private TenantContext tenantContext;

public ContextAwareCallable(Callable<T> task, TenantContext tenantContext)
{
    this.task = task;
    this.tenantContext = tenantContext;
}

@Override
public T call() throws Exception
{
    if (tenantContext != null)
    {
        return tenantContext.execute(tenantContext.getTenant().getId(), task);
    }

    return task.call();
    }
}

但它仍然没有给我父线程的正确租户。

对此有什么建议或其他方法吗?

谢谢, 没有

最佳答案

我通过直接在 contextawarecallable 构造函数中添加 tenantid 解决了这个问题。现在可以使用了。

关于java - Spring @async 子线程上下文 Multi-Tenancy ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48297362/

相关文章:

c++ - atomic fetch_add 与添加性能

java - 使用 DbUtils 将 ResultSet 转换为 TableModel 后,JTable 将设置为可编辑。如何再次使其不可编辑?

java - Spring Boot (1.3.5) - 默认错误 View

java - 如何持久保存数据以便我可以离线使用它们

hibernate - 使用 Spring 和 Hibernate 将读写事务路由到主事务,将只读事务路由到副本

java - @Resource 在 Spring 中不起作用?

java - hibernate 问题 : @OneToMany annotation returns duplicates

java - 传递一个类并调用它的方法

java - 如果当前线程 hibernate ,ThreadPoolExecutor 是否会生成新线程

c++ - 在多线程环境中将局部变量作为常量引用传递