Может ли EJB3 bean "ввести себя" и вызвать собственные методы через контейнер EJB?

Можно ли "самостоятельно вводить" 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 для управления своими собственными транзакциями и добавило бы много плиты котла ко всем методам.

Ответ 1

Обновление. Как отмечалось в других ответах, это действительно технически возможно. Пожалуйста, см. Ответы Csaba и Майкл о том, как и почему он работает, несмотря на бесконечную рекурсию. p >


Я не могу дать 100% точный ответ, но я уверен, что это невозможно.

Я так думаю, потому что для инъекции Foo bean в Foo bean сам контейнер первоначально должен был создать экземпляр Foo, который он может вставить потом. Но для его создания он должен ввести уже существующий экземпляр Foo в создаваемый Foo... который приводит к бесконечной рекурсии.

Если вам нужны отдельные транзакции, я бы предложил упростить задачу и создать два независимых интерфейса beans/.

Ответ 2

Самовозбуждение EJB действительно возможно. Причина, по которой бесконечная рекурсия не произойдет в этом случае, довольно проста: контейнер не вставляет фактический экземпляр bean из пула. Вместо этого он вводит прокси-объект. Когда вы вызываете метод на введенном прокси (foo), контейнер получает экземпляр bean из своего пула или создает его, если нет доступных экземпляров.

Ответ 3

Можно выполнить self injection. Вам нужно использовать SessionContext.

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

Ответ 4

Интересный вопрос. Я никогда не создаю метод с другим атрибутом транзакции в том же bean, то есть это требует рефакторинга. Обычно это затрудняет обнаружение ошибок в приложении, когда оно развивается.

EDIT: фиксированные опечатки

Ответ 5

Я бы не согласился, часто полезно, чтобы управление транзакциями вызывало локальный метод bean через контейнер.

В качестве примера, если вам нужно было вызвать локальный метод bean внутри цикла, вам лучше иметь транзакцию на итерацию, чем для всех итераций. (при условии, что бизнес-логика не "все или ничего", как отправка доставки или выпуск акций)