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