1

有一个会话范围的 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 为其创建代理并提交代理,但仍然遇到相同的错误。

感谢您对此的任何帮助!

4

1 回答 1

0

作为 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。但我根本不喜欢这种方法。上下文传播问题应该有更好的解决方案。

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

于 2016-04-09T20:58:26.697 回答