繁体   English   中英

开始CDI对话并将@ConversationScoped bean注入无状态会话bean

[英]Starting a CDI conversation and injecting @ConversationScoped bean into stateless session bean

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

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

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

与此相关的是,根据这个问题, 是否可以将@RequestScoped bean注入到@Stateless EJB中? 可以将ConservationScoped bean注入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

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

是的,因为MapBean@ConversationScoped它是从绑在调用链的持续时间起始conversation.begin()直到conversation.end() 您可以将@ConversationScoped (以及@RequestScoped@SessionScoped )视为ThreadLocal的实例-尽管每个线程都有一个实例,但每个实例都绑定到该单个线程。

与此相关的是,根据这个问题, 是否可以将@RequestScoped bean注入到@Stateless EJB中? 应该可以将@ConservationScoped bean注入SLSB,但这似乎有些神奇。 如果SLSB由其他进程(作业,UI调用等)使用,则是否为每个调用获取单独的实例?

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

除了您发布的链接之外,还请参见此答案

我已经测试了与您发布的代码类似的代码,并且可以按预期工作MapBean与整个调用中注入的代码相同。 请注意以下两点:

  • BatchJob也是@ConversationScoped但是没有实现Serializable ,这将不允许bean钝化。
  • data未初始化,因此您将在runJob()获得一个NPE。

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

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

如果您打算在调用的其他位置使用相同的实例,则可以通过将MapBean@ApplicationScoped Bean(或EJB @Singleton )来轻松实现。

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

在这里,我认为之所以如此神奇是因为SLSB就是CDI @Dependent bean。 如您所知,CDI总是为依赖的bean注入点创建新实例。 例如,是的,您为每个调用获得一个不同的SLS / Dependent bean实例。

也许其他范围更适合您? @RequestScoped@SessionScoped吗? 没有更多细节很难说。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM