【问题标题】:Getting different instances of @RequestScoped CDI bean during same request在同一请求期间获取 @RequestScoped CDI bean 的不同实例
【发布时间】:2016-05-15 07:48:15
【问题描述】:

在 WildFly 8/10 上,我有一个简单的 SLSB 触发 CDI 事件:

@Stateless
@Remote(CDITestRemote.class)
@Local(CDITestLocal.class)
public class CDITestBean implements CDITestRemote, CDITestLocal {

    @Inject
    private Event<IVolumeEvent> events;

    @Override
    public String insert(final String value) {
        final IVolumeEvent event = new VolumeEvent();
        events.fire(event);

        return String.format("value: %s", value);
    }
}

还有一个@ApplicationScoped“CDI 事件观察者”,用于 EJB 触发的事件类型:

@ApplicationScoped
public class VolumeEventObserver {

    private Logger logger = LoggerFactory.getLogger(VolumeEventObserver.class);

    @Inject
    private TransactionHandler txHandler;

    public void inProgress(
            @Observes(during = TransactionPhase.IN_PROGRESS) final IVolumeEvent event) {
        logger.info("@Observes progress() {}", String.valueOf(txHandler));
    }

    public void afterSuccess(
            @Observes(during = TransactionPhase.AFTER_SUCCESS) final IVolumeEvent event) {
        logger.info("@Observes success() {}", String.valueOf(txHandler));
    }

    public void afterFailure(
            @Observes(during = TransactionPhase.AFTER_FAILURE) final IVolumeEvent event) {
        logger.info("@Observes failure() {}", String.valueOf(txHandler));
    }

}

TransactionHandler@RequestScoped CDI bean:

@RequestScoped
public class TransactionHandler {
    // some methods here...    
}

当我在注入 REST 资源的 EJB 实例上调用 insert() 时,在对 REST 端点的请求期间,我在 VolumeEventObserver 的任何观察者方法中看到相同的 TransactionHandler 实例预期:

11:23:58,476 INFO  [VolumeEventObserver] (default task-11) @Observes progress() TransactionHandler@7687eead
11:23:58,479 INFO  [VolumeEventObserver] (default task-11) @Observes success() TransactionHandler@7687eead

但是当我进行远程 EJB 调用时,我在同一请求中看到 不同 个实例:

11:42:01,461 INFO  [VolumeEventObserver] (EJB default - 2) @Observes progress() TransactionHandler@2e65f10d
11:42:01,463 INFO  [VolumeEventObserver] (EJB default - 2) @Observes success() TransactionHandler@2a5a7019

所以TransactionHandler 似乎不在请求范围内。

JSR-299 表示请求范围处于活动状态:

在任何 EJB 的任何远程方法调用期间,在任何 任何 EJB 的异步方法调用 [...]

而且由于没有ContextNotActiveException,我想请求范围是活动的 - 那么为什么我会得到不同的实例呢?

这是同一个线程(从日志条目可以看出),事务也是一样的。

【问题讨论】:

  • 我不认为可以将 EJB 远程调用视为请求(嗯,至少在规范中),因此在此类调用期间使用 @RequestScoped bean 可能会产生危险的结果。
  • 我不明白你的意思 - 如果规范和 WELD 参考说“请求和应用程序范围也处于活动状态:在调用 EJB 远程方法期间”那么我只期望 @RequestScoped bean工作。
  • 你还有什么办法可以查出TransactionHandler是否相同?你可以在不同的对象上调用String.value(),代理同一个TransactionHandler实例(因为它是@RequestScoped,你得到一个代理而不是注入的真实实例)。
  • 好吧,我已经用 OpenEJB 测试了您的案例,并且得到了相同的 TransactionHandler 实例。也许这是wildfly的问题......
  • 谢谢,很高兴知道它可以与 OpenEJB 一起按预期工作!对于您之前的评论 - 我添加了一个 UUID 字段并且值不同。

标签: jakarta-ee ejb cdi


【解决方案1】:

您看到的行为符合规范。规范说请求上下文在远程 EJB 调用期间是活动的。它并不是说对同一个 bean 的重复调用在单个请求中运行。

【讨论】:

  • 这不是重复调用,而是一次调用,同一个线程,同一个事务。
  • 啊哈,重读你的问题后,我意识到你的问题是事务完成后你得到了不同的实例。
【解决方案2】:

只是在黑暗中拍摄:你试过用这个吗?

@ApplicationScoped
public class VolumeEventObserver {

    private Logger logger = LoggerFactory.getLogger(VolumeEventObserver.class);

    @Inject
    private Instance<TransactionHandler> txHandler;

    public void inProgress(
        @Observes(during = TransactionPhase.IN_PROGRESS) final IVolumeEvent event) {
        logger.info("@Observes progress() {}", String.valueOf(txHandler.get()));
    }

}

也许“实例”可以解决问题。

【讨论】:

  • 感谢您的建议,我会尝试一下。到目前为止,我实际上认为,当交易完成时,您不能指望发起交易的状态仍然存在,这是完全可以接受的。
猜你喜欢
  • 1970-01-01
  • 2014-06-02
  • 1970-01-01
  • 2013-11-22
  • 2021-05-22
  • 2016-12-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多