【问题标题】:Can an EJB3 bean "self inject" and call its own methods via EJB container?EJB3 bean 可以“自我注入”并通过 EJB 容器调用自己的方法吗?
【发布时间】:2010-10-12 15:10:12
【问题描述】:

是否可以“自注入”EJB 以将本地方法调用为 bean 方法?在某些情况下这可能是有利的,例如,如果使用容器管理的事务并且应该在新事务中完成某些事情。

这是如何工作的示例:

Foo.java:

@Local
public interface FoO {
    public void doSomething();
    public void processWithNewTransaction(); // this should actually be private
}

FooBean.java:

@Stateless
public class FooBean implements Foo {

    @EJB
    private Foo foo;

    public void doSomething() {
        ...
        foo.processWithNewTransaction();
        ...
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void processWithNewTransaction() {
        ...
    }
}

如果我将processWithNewTransaction() 提取到另一个bean,它需要在接口中作为公共方法公开,即使它只能由FooBean 调用。 (我上面的代码也有同样的问题,这就是接口定义中有注释的原因。)

一种解决方案是切换到 bean 管理的事务。但是,这需要更改整个 bean 来管理自己的事务,并且会为所有方法添加大量样板。

【问题讨论】:

  • 作为以下答案的补充:如果您不想在本地接口中使用新事务的方法,您可以使用 @Local(Foo.class)@LocalBean 注释您的 bean 实现并拥有该方法仅作为实现类中的公共方法。
  • OP - 请更新此选项以取消选中不正确的所选答案。

标签: java ejb-3.0


【解决方案1】:

可以使用self injection。您需要使用SessionContext

SessionContext sc = ...
sc.getBusinessObject(FooBean.class).processWithNewTransaction()

【讨论】:

【解决方案2】:

EJB 的自注入确实是可能的。在这种情况下不会发生无限递归的原因很简单:容器没有从池中注入实际的 bean 实例。相反,它注入了一个代理对象。当您在注入的代理 (foo) 上调用方法时,容器会从其池中获取一个 bean 实例,如果没有可用的实例,则创建一个。

【讨论】:

    【解决方案3】:

    更新:正如其他答案所指出的,这在技术上确实是可行的。请参阅 CsabaMichael 的答案,了解尽管出现了无穷无尽的递归,但它是如何以及为什么工作的。


    我无法给出 100% 准确的答案,但我很确定这是不可能的。

    我认为是因为要将 Foo bean 注入 Foo bean 本身,容器最初必须创建一个 Foo 实例,然后他可以将其注入。但是要创建它,他必须将一个已经存在的 Foo 实例注入到要创建的 Foo 中......这会导致无限递归。

    如果您需要单独的事务,我建议让事情变得简单并创建两个独立的 bean/接口。

    【讨论】:

    • 同意!会话 bean 的递归定义不是一个好主意。
    • 虽然建议分开,但确实有可能(见 michael nesterenko 回答)
    • 这对于 ejb 2.1 和 3+ 是可能的。要么你可以使用'@EJB Foo self;'或者你可以使用@michael nesterenko 的建议
    • 这个答案完全是错误的,不应被标记为正确。
    • @NBW 答案的技术错误已在大约两年前通过更新整合。它还引用了技术上更正确的答案。
    【解决方案4】:

    我倾向于不同意,通常通过容器调用本地 bean 方法对事务管理很有用。

    就像示例一样,如果您必须在循环内调用本地 bean 方法,那么每次迭代都有一个事务比所有迭代都要好。 (前提是业务逻辑不是像发货或发行股票那样“全有或全无”)

    【讨论】:

    • 这取决于您的业务需求
    【解决方案5】:

    有趣的问题。我从不在同一个 bean 中创建具有不同事务属性的方法,也就是说,这需要重构。这通常使得在应用程序发展时很难发现错误。

    编辑:修正错别字

    【讨论】:

    • 是否需要不同的 TX 属性甚至都没有关系。如果您只是想考虑您的逻辑,以便一种方法调用另一种方法有意义,例如您正在传递实体(需要保持在托管状态)或希望与相同的 TX 存在,您将遇到这种情况调用者或您希望调用拦截器。如果你不使用代理,这些事情都不会发生。
    • @NBW:我不怀疑它是否会发生。我只是说它使您的代码更难阅读并增加了错误调用该方法的机会,因为现在您可以通过多种方式进行操作。拥有一个单独的组件使其更易于维护。不过,您的里程可能会有所不同。
    猜你喜欢
    • 2015-11-24
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-29
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多