Jboss AS 6 - Как найти EJB через JNDI
Я пробую простой EJB 2.1 HelloWorld с использованием Jboss AS 6. Я создал EJB-файл JAR со следующей структурой:
HelloWorldEjb
|-ex1
|-ejb21
|-ejb.jar.xml
|-Hello.java
|-HelloBean.java
|-HelloHome.java
|-HelloLocal.java
|-HelloLocalHome.java
Я также создал клиентский автономный класс java для тестирования вышеупомянутого ejb. Я развернул файл jar с помощью консоли администратора Jboss 6 в разделе "Приложения> EJB2 jars" и нажал "Добавить новый ресурс". Когда я добавляю jar-файл, он дает мне это сообщение, поэтому я предполагаю, что он был правильно развернут.
Resource HelloWorldEjb.jar created successfully!
Теперь, когда я запускаю клиент, я получаю эту ошибку:
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
javax.naming.NameNotFoundException: HelloHome not bound
at org.jnp.server.NamingServer.getBinding(NamingServer.java:771)
at org.jnp.server.NamingServer.getBinding(NamingServer.java:779)
at org.jnp.server.NamingServer.getObject(NamingServer.java:785)
at org.jnp.server.NamingServer.lookup(NamingServer.java:443)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305)
at sun.rmi.transport.Transport$1.run(Transport.java:159)
at java.security.AccessController.doPrivileged(Native Method)
at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:619)
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142)
at org.jnp.server.NamingServer_Stub.lookup(Unknown Source)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:728)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:688)
at javax.naming.InitialContext.lookup(InitialContext.java:392)
at client.HelloClient.main(HelloClient.java:58)
Exception in thread "main" java.lang.NullPointerException
at client.HelloClient.main(HelloClient.java:72)
Сначала я подумал, что мне нужно настроить ресурс JNDI, для которого клиент будет использовать соединение для поиска EJB на сервере приложений. Это не обязательно? Пример, который я использую, использует имя EJB в операторе поиска. Вот раздел кода клиента для установления соединения.:
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://127.0.0.1:1099");
//env = new InitialContext(env);
InitialContext ctx = null;
try {
ctx = new InitialContext(env);
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Object obj = null;
try {
obj = ctx.lookup("HelloHome");
} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HelloHome home = (HelloHome) javax.rmi.PortableRemoteObject.narrow(obj, HelloHome.class);
А вот и содержимое ejb-jar.xml
<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instalce"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/ejb-jar_2_1.xsd"
version="2.1">
<enterprise-beans>
<session>
<ejb-name>HelloWorldEJB</ejb-name>
<home>ex1.ejb21.HelloHome</home>
<remote>ex1.ejb21.Hello</remote>
<local-home>ex1.ejb21.HelloLocalHome</local-home>
<local>ex1.ejb21.HelloLocal</local>
<ejb-class>ex1.ejb21.HelloBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
</ejb-jar>
Одна вещь, которая мне показалась интересной, это то, что когда я компилировал клиентский класс, он отказывался компилировать, если у него не было ссылки на класс HelloHome. Чтобы решить эту проблему, я должен был добавить файл jar ejb в classpath класса клиента. Это как это должно работать? т.е. файл ejb jar должен находиться на пути к классу клиента?
Что касается имени jndi, используемого для поиска, мне нужно создать новое имя? В приведенном выше примере, похоже, имя EJB используется в качестве поиска.
редактировать
В настоящее время я собираюсь прочитать книгу об EJB 3.0. Часть введения в EBJ 3.0 состоит в том, чтобы познакомить меня с вариантом 2.0, поэтому я и пробую этот пример. Я думаю, что имеет смысл хотя бы немного понять, как они работают, даже если я не планирую использовать EJB2.
Я посмотрел на консоль список развернутых приложений и не вижу свое приложение в пункте меню EJB2.0. Я думаю, это означает, что файл JAR не был правильно развернут. Журналы Jboss показывают, что он был развернут (см. 4-ую строку ниже).
16:36:50,982 INFO [org.rhq.core.pc.PluginContainer] Plugin Container initialized.
16:36:50,987 INFO [org.jboss.on.embedded.manager.pc.PluginContainerResourceManager] Discovering Resources...
16:36:50,988 INFO [org.rhq.core.pc.inventory.AutoDiscoveryExecutor] Executing server discovery scan...
16:36:53,920 INFO [org.rhq.core.pc.inventory.InventoryManager] Detected new Server [Resource[id=-3, type=JBossAS Server, key=C:\bin\appservers\jboss-6.1.0.Final\server\default, name=JBoss AS 6 (default), parent=<null>, version=6.1.0.Final]] - adding to local inventory...
16:36:54,032 INFO [org.rhq.core.pc.inventory.AutoDiscoveryExecutor] Found 0 servers.
16:36:54,032 INFO [org.rhq.core.pc.inventory.RuntimeDiscoveryExecutor] Running runtime discovery scan rooted at [platform]
16:36:54,093 INFO [org.rhq.core.pc.inventory.InventoryManager] Detected new Server [Resource[id=-4, type=JBoss AS JVM, key=JVM, name=JVM, parent=<null>, version=1.6.0_07]] - adding to local inventory...
16:36:54,097 INFO [org.rhq.plugins.jmx.JMXServerComponent] Starting connection to JMX Server JVM
16:36:54,695 INFO [org.rhq.core.pc.inventory.RuntimeDiscoveryExecutor] Scanned [0] servers and found [0] total descendant Resources.
Есть что-то, что выглядит неправильно в структуре, которую я описал выше?
редактировать
Хорошо, мне удалось решить это с помощью комментариев от Ричджа. Похоже, у меня был файл ejb-jar.xml в неправильном месте. Он должен был быть в папке META-INF. Я скопировал его из ext1/ejb21 в /META-INF, и jboss поднял файл jar.
17:21:44,376 INFO [org.rhq.core.pc.inventory.RuntimeDiscoveryExecutor] Scanned [0] servers and found [0] total descendant Resources.
17:21:45,301 INFO [org.jboss.ejb.plugins.local.BaseLocalProxyFactory] Unbind EJB LocalHome 'HelloWorldEJB' from jndi 'local/HelloWorldEJB@21777607'
17:21:45,349 INFO [org.jboss.proxy.ejb.ProxyFactory] Unbind EJB Home 'HelloWorldEJB' from jndi 'HelloWorldEJB'
17:21:45,358 INFO [org.jboss.ejb.EjbModule] Undeployed HelloWorldEJB
17:21:45,437 INFO [org.jboss.ejb.deployers.EjbDeployer] installing bean: ejb/#HelloWorldEJB,uid10624357
17:21:45,438 INFO [org.jboss.ejb.deployers.EjbDeployer] with dependencies:
17:21:45,439 INFO [org.jboss.ejb.deployers.EjbDeployer] and supplies:
17:21:45,440 INFO [org.jboss.ejb.deployers.EjbDeployer] jndi:HelloWorldEJB/ex1.ejb21.Hello
17:21:45,441 INFO [org.jboss.ejb.deployers.EjbDeployer] jndi:local/HelloWorldEJB@28622485
17:21:45,442 INFO [org.jboss.ejb.deployers.EjbDeployer] jndi:HelloWorldEJB/ex1.ejb21.HelloLocal
17:21:45,443 INFO [org.jboss.ejb.deployers.EjbDeployer] jndi:HelloWorldEJB
17:21:45,466 INFO [org.jboss.ejb.EjbModule] Deploying HelloWorldEJB
17:21:45,495 INFO [org.jboss.ejb.plugins.local.BaseLocalProxyFactory] Bound EJB LocalHome 'HelloWorldEJB' to jndi 'local/HelloWorldEJB@28622485'
17:21:45,503 INFO [org.jboss.proxy.ejb.ProxyFactory] Bound EJB Home 'HelloWorldEJB' to jndi 'HelloWorldEJB'
Я также внес небольшое изменение в файл xml, поскольку в используемых пространствах имен произошла опечатка.
Я использовал HelloWorldEJB в качестве имени jndi для клиента, и это, наконец, сработало.
Благодарю.
1 ответ
Я думаю, что ваше исключение означает либо:
- клиентский код использует неправильное имя для поиска EJB или...
- EJB не зарегистрирован в JNDI
Это работает?
obj = ctx.lookup("HelloHomeEJB");
Можно определить имя JNDI для удаленного дома, используя тег
Это как это должно работать? т.е. файл ejb jar должен находиться на пути к классу клиента?
Клиенту нужен доступ к интерфейсным классам. Самый простой способ - использовать файл ejb jar, но самый чистый способ - создать клиентскую версию файла ejb jar, которая не содержит ни одного из классов, относящихся только к реализации EJB.
Редактировать - файл JAR не развернут
Когда EJB развернут, что-то вроде этого должно быть записано в файл журнала:
18:49:33,979 INFO [EjbDeployer] installing bean: ejb/helloworld-ejb.jar#HelloWorld,uid181111540
18:49:33,979 INFO [EjbDeployer] with dependencies:
18:49:33,980 INFO [EjbDeployer] and supplies:
18:49:33,980 INFO [EjbDeployer] jndi:HelloWorldLocal
18:49:33,980 INFO [EjbDeployer] jndi:HelloWorld
Обычный способ развернуть файл JJ EJB - поместить его в каталог развертывания используемого вами сервера (будьте осторожны, стандартная установка JBoss обычно предоставляет более одной конфигурации сервера.) В моей системе каталог развертывания:
/usr/local/jboss/server/default/deploy
Иногда несколько файлов jar упакованы в файл ear. Метод развертывания такой же, но файл jar должен быть указан в дескрипторе развертывания META-INF/application.xml файла ear.