简体   繁体   English

EJB3 bean 可以“自我注入”并通过 EJB 容器调用自己的方法吗?

[英]Can an EJB3 bean “self inject” and call its own methods via EJB container?

Is it possible to "self inject" an EJB in order to call local methods as bean methods?是否可以“自注入”EJB 以将本地方法调用为 bean 方法? There are some cases where this could be favorable, for example if container managed transactions are used and something should be accomplished in a new transaction.在某些情况下这可能是有利的,例如,如果使用容器管理的事务并且应该在新事务中完成某些事情。

An example how this could work:这是如何工作的一个例子:

Foo.java: Foo.java:

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

FooBean.java: FooBean.java:

@Stateless
public class FooBean implements Foo {

    @EJB
    private Foo foo;

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

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

If I extract processWithNewTransaction() to another bean, it would need to be exposed as a public method in the interface, even though it should be called only by FooBean .如果我processWithNewTransaction()提取到另一个 bean,它需要在接口中作为公共方法公开,即使它应该只由FooBean (The same issue is with my code above, that's why there is a comment in the interface definition.) (我上面的代码也有同样的问题,这就是接口定义中有注释的原因。)

One solution would be to switch to bean managed transactions.一种解决方案是切换到 bean 管理的事务。 However this would require changing the whole bean to manage its own transactions, and would add a lot of boiler plate to all methods.然而,这将需要更改整个 bean 来管理它自己的事务,并且会为所有方法添加大量样板。

Self injection of a EJB is indeed possible. EJB 的自我注入确实是可能的。 The reason why an infinite recursion won't happen in this case is pretty simple: the container doesn't inject an actual bean instance from the pool.在这种情况下不会发生无限递归的原因很简单:容器没有从池中注入实际的 bean 实例。 Instead, it injects a proxy object.相反,它会注入一个代理 object。 When you call a method on the injected proxy (foo), the container gets a bean instance from its pool or creates one, if there are no available instances.当您在注入的代理 (foo) 上调用方法时,如果没有可用的实例,容器会从其池中获取一个 bean 实例或创建一个实例。

It is possible to do a self injection .可以进行self injection You need to use SessionContext .您需要使用SessionContext

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

Update : As noted by other answers, this is indeed technically possible.更新:正如其他答案所指出的,这在技术上确实是可行的。 Please see the answers of Csaba and Michael on how and why it works despite the apparend endless recursion.请参阅CsabaMichael的答案,了解它如何以及为什么会在看似无休止的递归的情况下起作用。


I cannot give a 100% accurate answer but I'm pretty sure that this is not possible.我无法给出 100% 准确的答案,但我很确定这是不可能的。

I think so because for injecting the Foo bean into the Foo bean itself the container would initially have to create a Foo instance which he can inject afterwards.我认为是这样,因为要将 Foo bean 注入 Foo bean 本身,容器最初必须创建一个 Foo 实例,然后他可以将其注入。 But to create this he has to inject an already existing instance of Foo into the Foo to be created... which leads to an infinite recursion.但是要创建它,他必须将一个已经存在的 Foo 实例注入到要创建的 Foo 中......这会导致无限递归。

If you need separate transactions I'd suggest to keep things easy and create two independend beans/interfaces.如果您需要单独的事务,我建议让事情变得简单并创建两个独立的 bean/接口。

I'd tend to disagree, often it's useful for transaction management to call a local bean method via the container.我倾向于不同意,通常通过容器调用本地 bean 方法对事务管理很有用。

Exactly as the example if you had to call a local bean method inside a loop you'd be better having a transaction per iteration than for all iterations.就像示例一样,如果您必须在循环中调用本地 bean 方法,那么每次迭代都有一个事务比所有迭代都要好。 (provided business logic wasn't "all or nothing" like despatching a delivery, or issuing stock) (前提是业务逻辑不是像发货或发行股票那样“全有或全无”)

Interesting question.有趣的问题。 I never create a method with a different transaction attribute in the same bean, that is, this begs for refactoring.我从不在同一个 bean 中创建具有不同事务属性的方法,也就是说,这需要重构。 This usually makes it hard to spot bugs in the application when it evolves.这通常使得在应用程序发展时很难发现应用程序中的错误。

EDIT: fixed typos编辑:修正错别字

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

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