Как клиент EJB находит сервер EJB без URL-адреса?

Я новичок в Java EE. В настоящее время я просматриваю учебник по Java EE 6, том 1 (бета-версия Basic Concepts) от Sun Microsystems. Чтобы избежать монотонного чтения времени, я играю с несколькими проектами/кодами Java EE, написанными другими.

Я приехал из SE. Моя голова все еще заполнена SE. В SE (двухуровневое приложение) я использую

DATABASE_URL = "jdbc:mysql://something.db_server.com/db_name"

Так мой клиент знает, где находится сервер базы данных.

В одном примере Java EE я увидел

// Access JNDI Initial Context.

Properties p = new Properties();

p.put("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
p.put("java.naming.provider.url","jnp://localhost:1099");
p.put("java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces");

InitialContext ctx = new InitialContext(p);

// Change jndi name according to your server and ejb

HelloRemote remote = (HelloRemote) ctx.lookup("HelloBean/remote");

msg = "Message From EJB --> " + remote.sayHello();

Это я понимаю. Код имеет URL-адрес и номер порта. Эта строка

p.put("java.naming.provider.url","jnp://localhost:1099");

Клиентская сторона знает, где находится сервер по URL-адресу, а какой порт - сбить. Я думаю, что код был написан во время Java EE 5.

Сегодня я нашел еще один пример использования Netbeans 7, Java EE 6 и GlassFish 3. Клиентский код

@EJB
private static MySessionRemote mySession;

/**
 * @param args the command line arguments
 */

public static void main(String[] args) {
    JOptionPane.showMessageDialog(null, 
            "result = " + mySession.getResult());
}

Вот ссылка http://netbeans.org/kb/docs/javaee/entappclient.html

Нет URL-адреса и номера порта.

Разработка Java EE 6 с Netbeans 7 Дэвидом Р. Хеффельфингеру аналогичным примером в главе 7. Автор не объяснил, как это делается в книге. Я думаю, что он это сделал, но я, вероятно, пропустил его...

Мой вопрос в том, как клиентская сторона находит сервер без URL-адреса? Это указано в одном из этих xml файлов? Клиент может находиться в Калифорнии, а сервер GlassFish - в Нью-Йорке. Может ли кто-нибудь объяснить это мне или указать на любой учебник/блог/статью, где я могу найти ответ?

Спасибо.

Ответ 1

Здесь есть две вещи.

Во-первых, способ, которым можно получить ссылку на удаленный EJB, не указан в Java EE. Вы во власти того, как отдельный поставщик считает, что это должно быть сделано.

Хотя JNDI является стандартом де-факто, используемым для этого, даже это само по себе не является обязательным.

Пример: JBoss до AS7

В JBoss AS вплоть до AS 7 для получения удаленной ссылки использовалась следующая последовательность:

Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
env.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces");
env.put(Context.PROVIDER_URL, "jnp://myserver.example.com:1099");
InitialContext context = new InitialContext(env);

Bean bean = (Bean) context.lookup("myear/MyBean/remote");

Здесь URL-адрес удаленного сервера предоставляется в исходный контекст, и из этого контекста извлекается bean. (Обратите внимание, что вы должны НЕ добавить известный префикс java:/"здесь, иначе он будет перехвачен JNDI и разрешен локально, несмотря на поиск в удаленном контексте)

Поскольку этот метод упоминался как не стандартизованный, один поставщик может полностью изменить его между версиями реализаций. Даже для реализаций для той же версии Java EE.

Пример: JBoss AS7

В JBoss AS 7 JBoss хотел отойти от JNDI (потому что не было указано, что JNDI нужно было использовать), и теперь это происходит примерно в следующим образом:

Сначала вам нужно поместить файл jboss-ejb-client.properties в свой путь к классам со следующим контекстом:

endpoint.name = client-endpoint
remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED = false
remote.connections = default
remote.connection.default.host = myserver.example.com
remote.connection.default.port = 4447
remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS = false

И используйте код следующим образом:

Properties env = new Properties();
env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
InitialContext context = new InitialContext(env);

Bean bean = (Bean) context.lookup("ejb:/myear/mymodule/MyBean!com.example.Bean");

Итак, из кода видно, что URL не указан, но он статически скрыт в файле конфигурации.


Контейнер клиентских приложений

Сегодня я нашел еще один пример использования Netbeans 7, Java EE 6 и GlassFish 3. Код на стороне клиента [...]

Это еще одна вещь. То, что было продемонстрировано, - это так называемый Контейнер клиентских приложений (aka ACC).

Это отличается от приведенного выше примера, когда приложение Java SE использовало JNDI для связи с удаленным сервером. Контейнер клиентских приложений немного неясен в Java EE. Идея заключается в том, что вы динамически загружаете клиентский код с сервера (например, приложение Applet или Java Web Start), и затем оно волшебным образом "знает", откуда оно возникло. Существует очень ограниченная поддержка (статической) инъекции в основном классе, которую вы можете использовать для непосредственного ввода удаленного beans.

Контейнер клиентских приложений представляет собой идею с первых дней Java EE, и, насколько я знаю, никогда не получал много внимания. После всех этих лет он никогда не продвигался много после своей первоначальной концепции. Поскольку для этого все еще требуется тонна конкретных вещей для поставщиков, я думаю, что большинство людей не беспокоится об этом и просто использует JNDI.

Ответ 2

В этом случае должен быть файл jndi.properties с данными конфигурации. Клиент не может магически знать сервер для подключения, даже если ему нужно будет подключиться к серверу, работающему на том же хосте, что и клиент, - все равно может быть несколько.

Пример очень странный, но аннотация EJB указывает, что он должен запускаться в контейнере Java EE, а не как клиентское приложение.

Я также хотел бы отметить, что вызов EJB в клиентских приложениях не так уж и важен; это скорее серверная технология. Если вы хотите предоставить интерфейс для клиентских приложений, это гораздо проще и более переносимо для использования, например, веб-сервисов RESTful через JAX-RS.