Статьи

Наследование EJB отличается от наследования Java

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