【问题标题】:Is there a way to propagate SessionContext to a new thread (getting WELD-001303)?有没有办法将 SessionContext 传播到新线程(获取 WELD-001303)?
【发布时间】:2016-04-08 08:29:25
【问题描述】:

有一个会话范围的 bean 'Identity',我将它注入到实现 Runnable 的 @Stateless bean 中:

@Stateless
@LocalBean
public class Test implements Runnable {
    @Inject
    Identity identity;
    @Inject
    Logger log;

    @Override
    public void run() {
        log.warn("Test: " + this + " " + identity.getAccount().getId());
    }
}

还有一个 bean 可以异步调用上述 Runnable:

@Stateless
@LocalBean
public class BeanContextExecutor implements Executor {
    @Asynchronous
    @Override
    public void execute(Runnable command) {
        command.run();
    }
}

最后,调用看起来像这样:

@Stateless
public class OtherBean {
    @Inject
    BeanContextExecutor executor;
...
        executor.execute(command);
...
}

运行时出现以下错误:

...
Caused by: org.jboss.weld.context.ContextNotActiveException: WELD-001303: No active contexts for scope type javax.enterprise.context.SessionScoped
...

有没有办法将 SessionContext 传播到后台线程?

我还尝试将此 Runnable 提交给 ManagedExecutorService,甚至使用 ContextService 为其创建代理并提交代理,但仍然遇到相同的错误。

感谢您对此的任何帮助!

【问题讨论】:

    标签: jboss ejb wildfly weld picketlink


    【解决方案1】:

    作为 BeanContextExecutor 中的一种解决方法,我使用 BoundSessionContext 为新线程创建虚拟会话上下文,并且还必须手动复制所需的会话 bean 以使其状态在后台线程中可用:

    @Inject
    BoundSessionContext boundSessionContext;
    // Backed by a ConcurrentHashMap<Runnable, Identity> which stores the state of the session scoped bean before spawning a new thread
    @Inject
    GlobalExecutionContext globalExecutionContext;
    @Inject
    Instance<Identity> identityInstance;
    @Inject
    Cloner cloner;
    @Inject
    private BeanManager beanManager;
    
    @Asynchronous
    @Override
    public void execute(Runnable command) {
        HashMap<String, Object> storage = new HashMap<>();
        boundSessionContext.associate(storage);
        boundSessionContext.activate();
    
        Identity identity = globalExecutionContext.remove(command);
        Bean<Identity> bean = (Bean<Identity>) beanManager.resolve(beanManager.getBeans(Identity.class));
        Identity localIdentity = beanManager.getContext(bean.getScope()).get(bean, beanManager.createCreationalContext(bean));
    
        cloner.copyPropertiesOfInheritedClass(identity, localIdentity);
    
        command.run();
    
        boundSessionContext.invalidate();
        boundSessionContext.deactivate();
        boundSessionContext.dissociate(storage);
    }
    

    该示例旨在演示该方法,可以对其进行改进,例如支持传递任意类型的 bean。但我根本不喜欢这种方法。上下文传播问题应该有更好的解决方案。

    更新: 即使初始会话已过期,我也想将调用者身份保留在后台线程中,看起来上述解决方案适合此。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-29
      • 1970-01-01
      • 2016-11-27
      • 1970-01-01
      • 2011-11-07
      • 1970-01-01
      • 2023-03-12
      • 1970-01-01
      相关资源
      最近更新 更多