Несколько экземпляров с отслеживанием состояния объекта EJB при введении через КДИ


Речь идет в основном о понимании различий при введении статусного EJB (SFSB) с @Inject по сравнению с инъекцией его с @EJB.

Одним из главных отличий должно быть контекстуальное осознаниепри инъекции через @Inject. Таким образом, мое предположение состояло в том, что если я создам два @RequestScoped Боба и введу в каждый SFSB дважды (один раз с @Inject, один раз с @EJB), SFSB, введенный через @Inject, будет одним и тем же экземпляром в обоих @RequestScoped бобы , тогда как те, которые вводятся через @EJB, будут различными экземплярами. Это предположение кажется неправильным, но я не понимаю, почему. Не следует ли CDI осознавать тот факт, что оба Боба являются @RequestScoped и, следовательно, вводят один и тот же 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 Боб:

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;
    }

}

Есть еще один @RequestScoped боб с именем MySecondRequestScoped и аналогичная реализация.

Когда они вызываются со страницы JSF xhtml через EL (ничего особенного, просто <h:outputText value="#{myFirstRequestScoped.myStatefulByCDI}" /> и так далее, чтобы вызвать их создание), это вывод консоли (WebSphere ApplicationServer 8.5.5.0):

[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

Итак, кажется, что:

  • созданы 4 экземпляра SFSB ; я ожидал бы, что это будет всего 3. Те, кто вводится через @EJB, не знают контекста, поэтому я бы подумал, что это нормально, если они создано для каждой точки впрыска. Но поскольку CDI должен быть осведомлен о контексте (@RequestScoped), я подумал, что CDI будет повторно проецировать уже созданный SFSB.
  • единственное различие между @Inject и @EJB, по-видимому, заключается в том, что жизненный цикл автоматически управляется при введении через CDI - метод с аннотацией @PreDestroy называется для тех (36b3bb10 и 456cec27). Они вводятся через @EJB (c03fcdee и 9b3971c7) позже только пассивируются и, кажется, не разрушаются в любое время позже.
Последнее, по-видимому, является хорошей причиной для использования @Inject вместо @EJB, но я не понимаю, что на самом деле подразумевается под контекстуальным осознанием CDI, Когда есть новый экземпляр SFSB, созданный независимо от области видимости?

Кстати, то же самое происходит и при использовании @SessionScoped бобы, даже если второй Боб создан после перехода по ссылке на другую страницу (чтобы убедиться, что SFSB, введенный через @Inject, определенно существует уже). Более того, SFSB экземпляры , вводимые через @EJB, создаются только один раз в течение всего времени сеанса, так же как и те, которые вводятся через @Inject - так что они, похоже, тоже каким-то образом осознают контекст...? При смешивании @SessionScoped и @RequestScoped бобов, Боб @SessionScoped получает другой экземпляр SFSB инъецируется, чем @RequestScoped боб, что прекрасно , но, похоже, не является особенностью CDI, так как это верно для обоих тех экземпляров SFSB вводится через @Inject , а также для тех, кто вводится через @EJB.

Редактировать: вывод наблюдаемого поведения: Единственное различие между введением SFSB через @Inject и @EJB, по-видимому, состоит в том, что в первом случае SFSB автоматически уничтожается, когда область остается, а во втором-нет. Это правильно? Это показалось бы мне странным, так как я ожидал, что CDI будет вести себя иначе...

Любые намеки на то, что я упускаю, т. е. непонимание, когда это доходит до "С" в "CDI"? Надеюсь, это не какая-то там "специальность"...

1 3

1 ответ:

Для того, чтобы ваш SFSB был ограничен запросом, вам нужно дать ему область @RequestScoped. Затем вы должны увидеть, как вводится тот же экземпляр. Теперь, поскольку оба они являются прокси, самый простой способ подтвердить-установить некоторое значение из одного Боба и получить значение из другого Боба.