1

已经提出了类似的问题,但并没有完全解决我想要做的事情。我们有一个旧的基于 Seam 2.x 的应用程序,带有一个我们正在转换为 CDI 的批处理作业框架。作业框架使用 Seam Contexts 对象来启动对话。作业框架还加载了一个特定于作业的数据持有者(基本上是一个地图),然后可以通过 Seam Contexts 对象由链下的任何服务访问,包括来自 SLSB。其中一些服务可以更新地图,以便作业状态可以更改并从记录到记录进行检测。

看起来在 CDI 中,作业将@Inject是一个 CDI 对话对象,并手动开始/结束对话。我们还将定义一个ConversationScoped包含 Map ( MapBean) 的新 bean。我不清楚的是两件事:

首先,作业还需要@InjectMapBean以便在调用 Conversation.begin() 方法之前加载作业特定的数据。容器是否知道将此实例传递给调用链中的服务?

与此相关,根据这个问题Is it possible to @Inject a @RequestScoped bean into a @Stateless EJB? 应该可以将ConservationScopedbean 注入到 SLSB 中,但这似乎有点神奇。如果 SLSB 被不同的进程(作业、UI 调用等)使用,它是否会为每个调用获取单独的实例?

为澄清和简化的类结构而进行的编辑:

MapBean需要是一个ConversationScoped对象,包含作业的特定实例/运行的数据。

@ConversationScoped
public class MapBean implements Serializable {
    private Map<String, Object> data;
    // accessors
    public Object getData(String key) {
        return data.get(key);
    }
    public void setData(String key, Object value) {
        data.put(key, value);
    }

}

工作将是ConversationScoped

@ConversationScoped
public class BatchJob {
    @Inject private MapBean mapBean;
    @Inject private Conversation conversation;
    @Inject private JobProcessingBean jobProcessingBean;
    public void runJob() {
        try {
            conversation.begin();
            mapBean.setData("key", "value");  // is this MapBean instance now bound to the conversation?
            jobProcessingBean.doWork();
        } catch (Exception e) {
            // catch something
        } finally {
            conversation.end();
        }
    }
}

该作业可能调用 SLSB,并且当前会话范围的实例MapBean需要可用:

@Stateless
public class JobProcessingBean {
    @Inject private MapBean mapBean;

    public void doWork() {
        // when this is called, is "mapBean" the current conversation instance?
        Object value = mapBean.getData("key");
    }
}

我们的工作和 SLSB 框架相当复杂,SLSB 可以调用许多其他服务或本地实例化的业务逻辑类,并且每个都需要访问会话范围的MapBean.

4

2 回答 2

4

首先,作业还需要@Inject在调用方法MapBean之前加载特定于作业的数据。Conversation.begin()容器是否知道将此实例传递给调用链中的服务?

是的,因为MapBean@ConversationScoped在从conversation.begin()until开始的持续时间内与调用链相关联conversation.end()。您可以将@ConversationScoped(and @RequestScopedand @SessionScoped) 视为 in ThreadLocal- 虽然每个线程都存在它们的实例,但每个实例都与该单个线程相关联。

与此相关,根据这个问题Is it possible to @Inject a @RequestScoped bean into a @Stateless EJB? 应该可以将@ConservationScopedbean 注入到 SLSB 中,但这似乎有点神奇。如果 SLSB 被不同的进程(作业、UI 调用等)使用,它是否会为每个调用获取单独的实例?

如果您看到这种模式与我上面解释的模式相同,它并没有您想象的那么神奇。SLSB 确实获得了一个单独的实例,但不只是任何实例,它属于调用 SLSB 的范围。

除了您发布的链接,另请参阅此答案

我已经测试了与您发布的代码类似的代码,它按预期工作 - 在MapBean整个调用过程中注入的代码相同。请注意两件事:

  • BatchJob也是@ConversationScoped但不实现Serializable,这将不允许 bean 钝化。
  • data未初始化,因此您将在runJob().
于 2017-11-29T21:49:59.893 回答
0

没有任何代码示例,我将不得不做一些猜测,所以让我们看看我是否正确。

容器是否知道将此实例传递给调用链中的服务?

如果您打算在调用的其他地方使用相同的实例,那么可以通过制作MapBean一个@ApplicationScopedbean(或者,或者,和 EJB @Singleton)来轻松实现。

应该可以将 ConservationScoped bean 注入 SLSB,但这似乎有点神奇。

在这里,我想之所以看起来很神奇,是因为 SLSB 在 CDI 方面是一个@Dependentbean。您可能知道,CDI 总是为依赖 bean 注入点创建新实例。例如,是的,每次调用都会得到一个不同的 SLS/Dependent bean 实例。

也许其他一些范围更适合您?喜欢@RequestScoped还是@SessionScoped?没有更多细节很难说。

于 2017-11-28T06:23:46.667 回答