Несмотря на то, что наследование 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
|
@Stateless public 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
|
@Stateless public 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 Петра Новицки в блоге Петра Новицкого на домашней странице .