Dependency injection 通过CDI注入时有状态EJB的多个实例

Dependency injection 通过CDI注入时有状态EJB的多个实例,dependency-injection,java-ee-6,cdi,ejb-3.1,websphere-8,Dependency Injection,Java Ee 6,Cdi,Ejb 3.1,Websphere 8,这主要是关于理解在使用@Inject注入有状态的EJB(SFSB)时与使用@EJB注入时的差异 主要区别之一应该是通过@Inject注入时的上下文意识。因此,我的假设是,如果我创建两个@RequestScopedbean,并在每个bean中注入SFSB两次(一次使用@inject,一次使用@EJB),那么通过@inject注入的SFSB将是这两个@RequestScopedbean中的相同实例,而通过@EJB注入的将是不同的实例 这个假设似乎是错误的,但我不明白为什么。CDI是否应该意识到两个b

这主要是关于理解在使用
@Inject
注入有状态的
EJB
SFSB
)时与使用
@EJB
注入时的差异

主要区别之一应该是通过
@Inject
注入时的上下文意识。因此,我的假设是,如果我创建两个
@RequestScoped
bean,并在每个bean中注入
SFSB
两次(一次使用
@inject
,一次使用
@EJB
),那么通过
@inject
注入的
SFSB
将是这两个
@RequestScoped
bean中的相同实例,而通过
@EJB
注入的将是不同的实例

这个假设似乎是错误的,但我不明白为什么。
CDI
是否应该意识到两个bean都是
@requestscope
的,因此注入相同的
SFSB
?为什么不是这样,或者我的测试代码有点缺陷

这是我的
SFSB
及其界面:

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Local;
import javax.ejb.PrePassivate;
import javax.ejb.Stateful;

import package.MyStateful;

@Stateful
@Local(MyStateful.class)
public class MyStatefulImpl implements MyStateful {

    @PostConstruct
    private void postConstruct() {
            System.out.println("SFSB postconstruct ref: " + this.toString());
    }

    @PreDestroy
    private void preDestroy() {
            System.out.println("SFSB predestroy ref: " + this.toString());
    }

    @PrePassivate
    private void prePassivate() {
            System.out.println("SFSB prepassivate ref: " + this.toString());
    }

    @Override
    public String myToString() {
            return toString();
    }
}

public interface MyStateful {
    String myToString();
}
这是一个
@RequestScoped
bean:

import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.inject.Inject;
import javax.inject.Named;

import package.MyStateful;

@Named
@RequestScoped
public class MyFirstRequestScoped {

    @Inject
    MyStateful myStatefulByCDI;

    @EJB
    MyStateful myStatefulByEJB;

    public MyStateful getMyStatefulByCDI() {
            System.out.println("first#myStatefulByCDI proxy ref: " + myStatefulByCDI.toString());
            System.out.println("first#myStatefulByCDI stateful ref: " + myStatefulByCDI.myToString());
            return myStatefulByCDI;
    }

    public MyStateful getMyStatefulByEJB() {
            System.out.println("first#myStatefulByEJB proxy ref: " + myStatefulByEJB.toString());
            System.out.println("first#myStatefulByEJB stateful ref: " + myStatefulByEJB.myToString());
            return myStatefulByEJB;
    }

}
还有另一个名为MySecondRequestScoped的
@RequestScoped
bean,具有类似的实现

当通过
EL
JSF
xhtml页面调用它们时(没有什么特别的,只是一个
等等来触发它们的创建),这就是控制台输出(WebSphere ApplicationServer 8.5.5.0):

看来:

  • 创建了4个SFSB实例;我本以为这只会3个。那些通过
    @EJB
    注入的对象不知道上下文,所以我认为如果为每个注入点创建它们就可以了。但是由于
    CDI
    应该知道上下文(
    @RequestScoped
    ),我认为
    CDI
    会重新注入已经创建的
    SFSB
  • @Inject
    @EJB
    之间的唯一区别似乎在于,当通过
    CDI
    注入时,生命周期是自动管理的-为那些调用带注释的
    @PreDestroy
    方法(36b3bb10和456cec27)。通过
    @EJB
    (c03fcdee和9b3971c7)注入的这些之后仅被钝化,并且似乎不会在任何时候被破坏
后者似乎是使用
@Inject
而不是
@EJB
的一个很好的理由,但我不明白的是,当创建了一个新的
SFSB
实例而不管其范围如何时,
CDI
上下文意识到底意味着什么

顺便说一句,当使用
@SessionScoped
bean时,即使第二个bean是在链接到另一个页面后创建的(以确保通过
@Inject
注入的
SFSB
肯定已经存在),这种行为也是一样的。此外,通过
@EJB
注入的
SFSB
实例在会话的生命周期内只创建一次,就像通过
@Inject
注入的实例一样-因此它们似乎也知道上下文,不知何故。。。?当混合使用
@SessionScoped
@RequestScoped
bean时,
@SessionScoped
bean比
@RequestScoped
bean注入了
SFSB的另一个实例,这很好,但似乎不是CDI的一个特性,因为这对于通过
@Inject
注入的
SFSB
实例和通过
@EJB
注入的
实例都是如此

编辑:观察行为的结论: 通过
@Inject
@EJB
注入
SFSB
的唯一区别在于,在前一种情况下,当作用域离开时,
SFSB
会自动销毁,而在后一种情况下则不会。这是正确的吗?这让我觉得很奇怪,因为我希望
CDI
的行为会有所不同


有没有关于我遗漏了什么的提示,即当涉及到“
CDI
”中的“C”时存在误解?我希望这不是什么WebSphere“专业”…

为了使您的SFSB的作用域适合于请求,您需要给它
@RequestScoped
作用域。然后您应该看到注入了相同的实例。现在,由于这两个都是代理的,最简单的确认方法是从一个bean设置一些值,然后从另一个bean获取值。

@EJB
似乎来自与CDI不同的技术时代。当然,
@EJB
CDI
存在的时间要长得多,CDI是自版本6以来JavaEE的一部分(请参阅)。但遗憾的是,对我来说,这并不能解释我上面解释的行为。好吧,这起作用了。。。检查了toString ID,所以我知道它是相同的
SFSB
。因此,这就像“在使用CDI注入
SFSB
时,为了获得
SFSB
的正确实例,
SFSB
必须有一个范围注释”?我发现这相当令人困惑,因为当我决定更改我的web层以使用另一个作用域时(例如,由于我拆分了一个页面并使某些进程成为多个页面上的向导,所以使用对话而不是请求),我还必须更改EJB上的作用域注释?我似乎误解了这里的一些概念。您如何以最佳实践方式将
SFSB
s与CDI结合使用?范围界定是适当的。在大多数情况下,我不使用SFSB,而是在我的应用程序中使用无状态。在这些情况下,我不提供范围。如果需要的话,有状态的性质将出现在一个纯CDI对象中!我从另一个角度看,我想我应该有一个
SFSB
,正如你所说的,如果需要,我会添加一个范围,即。
[1/4/14 12:39:11:759 CET] 000000dc SystemOut     O SFSB postconstruct ref: package.MyStatefulImpl@c03fcdee
[1/4/14 12:39:11:761 CET] 000000dc SystemOut     O SFSB postconstruct ref: package.MyStatefulImpl@36b3bb10
[1/4/14 12:39:11:761 CET] 000000dc SystemOut     O first#myStatefulByCDI proxy ref: package.EJSLocal0SFMyStatefulImpl_8d170245@48da7f98(BeanId(Project#ProjectEJB.jar#MyStatefulImpl, 5D0CBA11-0143-4000-E000-6A007F000001))
[1/4/14 12:39:11:762 CET] 000000dc SystemOut     O first#myStatefulByCDI stateful ref: package.MyStatefulImpl@36b3bb10
[1/4/14 12:39:11:768 CET] 000000dc SystemOut     O SFSB postconstruct ref: package.MyStatefulImpl@9b3971c7
[1/4/14 12:39:11:768 CET] 000000dc SystemOut     O SFSB postconstruct ref: package.MyStatefulImpl@456cec27
[1/4/14 12:39:11:769 CET] 000000dc SystemOut     O second#myStatefulByCDI proxy ref: package.EJSLocal0SFMyStatefulImpl_8d170245@48da7fa1(BeanId(Project#ProjectEJB.jar#MyStatefulImpl, 5D0CBA18-0143-4000-E001-6A007F000001))
[1/4/14 12:39:11:769 CET] 000000dc SystemOut     O second#myStatefulByCDI stateful ref: package.MyStatefulImpl@456cec27
[1/4/14 12:39:11:769 CET] 000000dc SystemOut     O first#myStatefulByEJB proxy ref: package.EJSLocal0SFMyStatefulImpl_8d170245@48da7f9b(BeanId(Project#ProjectEJB.jar#MyStatefulImpl, 5D0CBA0E-0143-4000-E000-6A007F000001))
[1/4/14 12:39:11:769 CET] 000000dc SystemOut     O first#myStatefulByEJB stateful ref: package.MyStatefulImpl@c03fcdee
[1/4/14 12:39:11:769 CET] 000000dc SystemOut     O second#myStatefulByEJB proxy ref: package.EJSLocal0SFMyStatefulImpl_8d170245@48da7fa1(BeanId(Project#ProjectEJB.jar#MyStatefulImpl, 5D0CBA18-0143-4000-E000-6A007F000001))
[1/4/14 12:39:11:770 CET] 000000dc SystemOut     O second#myStatefulByEJB stateful ref: package.MyStatefulImpl@9b3971c7
[1/4/14 12:39:11:848 CET] 000000dc SystemOut     O SFSB predestroy ref: package.MyStatefulImpl@36b3bb10
[1/4/14 12:39:11:849 CET] 000000dc SystemOut     O SFSB predestroy ref: package.MyStatefulImpl@456cec27
[1/4/14 12:50:11:765 CET] 00000120 SystemOut     O SFSB prepassivate ref: package.MyStatefulImpl@c03fcdee
[1/4/14 12:50:11:766 CET] 00000120 SystemOut     O SFSB prepassivate ref: package.MyStatefulImpl@9b3971c7