Несмотря на то, что наследование EJB иногда использует наследование Java — они не всегда одинаковы. Как вы могли прочитать в моем предыдущем посте , EJB не нужно реализовывать какой-либо интерфейс для представления бизнес-интерфейса.
Обратный путь также верен — тот факт, что EJB реализует некоторый интерфейс или расширяет другой EJB, не означает, что он раскрывает все или некоторые из его представлений.
Допустим, мы хотим иметь некоторый базовый EJB-компонент, представляющий удаленный бизнес-интерфейс. Затем мы хотим расширить этот EJB и переопределить удаленные бизнес-методы.
Ничего особенного, правда? Но давайте посмотрим на некоторые примеры.
Удаленный бизнес-интерфейс:
|
1
2
3
|
public interface RemoteA { void remoteA();} |
База EJB:
|
1
2
3
4
5
6
7
|
@Stateless@Remote(RemoteA.class) public class SuperclassEJB implements RemoteA { public void remoteA() { // Some basic code that can be overriden. }} |
Вышеупомянутый SuperclassEJB является нашим базовым EJB. Он предоставляет один удаленный бизнес-интерфейс одним методом. Теперь давайте перейдем к подклассам нашего EJB:
Случай 1 — Наследование Java
|
1
2
3
4
|
@Statelesspublic class SubclassEJB1 extends SuperclassEJB { // 'remoteA' is not EJB business method. EJB inheritance is strictly for implementation reusing.} |
SubclassEJB1 — это EJB — это точно. Но какие интерфейсы он предоставляет? Поскольку компонент EJB должен явно определять, какие бизнес-интерфейсы он определяет, — у нашего EJB вообще нет никаких реальных бизнес-методов! Это новый, свежий интерфейс без интерфейса EJB.
Это означает, что если в вашем коде вы будете делать:
-
@EJB SubclassEJB1 myEJBэто@EJB SubclassEJB1 myEJBваш EJB-представление без интерфейса без каких-либо бизнес-методов. -
@EJB(name='SubclassEJB1') RemoteA myEJBоткажется делать эту инъекцию, посколькуRemoteAне является бизнес-интерфейсом нашего EJB.
Что интересно — если вместо внедрения контейнера с помощью @EJB вы сделаете поиск следующим образом:
|
1
2
|
RemoteA subclassEJB1 = (RemoteA) initialContext.lookup('java:module/SubclassEJB1');subclassEJB1.remoteA(); |
он не будет remoteA() никаких исключений и правильно вызывать метод remoteA() . Почему? Потому что то, что мы действительно искали, было представлением нашего EJB без интерфейса. Затем мы RemoteA его к RemoteA (что правильно с точки зрения Java) и RemoteA метод представления без интерфейса. Я думаю, вы согласитесь, что это может быть довольно запутанным — вместо того, чтобы использовать удаленный интерфейс, мы получили правильный метод локального компонента.
Случай 2 — Наследование Java с реализацией интерфейса
|
1
2
3
4
5
|
@Statelesspublic class SubclassEJB2 extends SuperclassEJB implements RemoteA { // 'remoteA' is correctly exposed as EJB business method BUT as an implicit local i-face. // Method implementation is correctly inherited.} |
Теперь это выглядит очень странно. Наш EJB расширяет другой EJB и реализует удаленный бизнес-интерфейс, верно? Ну, не совсем так. Мы реализуем простой интерфейс Java RemoteA . Этот интерфейс сам по себе не имеет аннотации @Remote и SuperclassEJB . Это означает, что мы представляем RemoteA как локальный бизнес-интерфейс . Это одно из поведений EJB по умолчанию, которое обсуждалось в моем предыдущем посте .
Это означает, что если в вашем коде вы будете делать:
-
@EJB(name='SubclassEJB2') RemoteA myEJBбудет использовать локальный бизнес-интерфейс. Довольно запутано, не так ли?
Случай 3 — Наследование Java с реализацией интерфейса и объявлением представления
|
1
2
3
4
5
6
|
@Stateless@Remote(RemoteA.class) public class SubclassEJB3 extends SuperclassEJB { // Method 'remoteA' is correctly exposed as EJB business method (thanks to @Remote on EJB). // Method implementation is correctly inherited.} |
Это правильный пример расширения EJB. Мы правильно использовали реализацию с наследованием Java, реализовали удаленный бизнес-интерфейс EJB и показали его с помощью @Remote . Предложение @Remote даже не требуется — @Remote будет достаточно. Тем не менее, часть @Remote имеет решающее значение.
Это означает, что если в вашем коде вы будете делать:
-
@EJB(name='SubclassEJB3') RemoteA myEJBбудет правильно использовать удаленный бизнес-интерфейс.
Вывод
Как вы можете видеть, наследование EJB иногда может быть не таким легким, как ожидалось. Требуется знание основ определения компонентов и представлений. По умолчанию наследование компонента предназначено для повторного использования кода, а не для расширения компонента. Без этих знаний вы можете столкнуться с некоторыми довольно странными и разочаровывающими проблемами. Все примеры были протестированы на JBoss AS 7.1.1.
Справка: Наследование EJB отличается от Наследования Java от нашего партнера по JCG Петра Новицки в блоге Петра Новицкого на домашней странице .