ejb 查找失败并出现 NamingException
Posted
技术标签:
【中文标题】ejb 查找失败并出现 NamingException【英文标题】:ejb lookup failing with NamingException 【发布时间】:2009-09-24 20:23:35 【问题描述】:我在 web.xml 中添加了以下内容:
<ejb-ref>
<ejb-ref-name>ejb/userManagerBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>gha.ywk.name.entry.ejb.usermanager.UserManagerHome</home>
<remote>what should go here??</remote>
</ejb-ref>
下面的 java 代码给了我 NamingException:
public UserManager getUserManager () throws HUDException
String ROLE_JNDI_NAME = "ejb/userManagerBean";
try
Properties props = System.getProperties();
Context ctx = new InitialContext(props);
UserManagerHome userHome = (UserManagerHome) ctx.lookup(ROLE_JNDI_NAME);
UserManager userManager = userHome.create();
WASSSecurity user = userManager.getUserProfile("user101", null);
return userManager;
catch (NamingException e)
log.error("Error Occured while getting EJB UserManager" + e);
return null;
catch (RemoteException ex)
log.error("Error Occured while getting EJB UserManager" + ex);
return null;
catch (CreateException ex)
log.error("Error Occured while getting EJB UserManager" + ex);
return null;
代码在容器内使用。我的意思是 .WAR 部署在服务器(Sun Application Server)上。
StackTrace(根据 jsight 的建议):
>Exception occurred in target VM: com.sun.enterprise.naming.java.javaURLContext.<init>(Ljava/util/Hashtable;Lcom/sun/enterprise/naming/NamingManagerImpl;)V
java.lang.NoSuchMethodError: com.sun.enterprise.naming.java.javaURLContext.<init>(Ljava/util/Hashtable;Lcom/sun/enterprise/naming/NamingManagerImpl;)V
at com.sun.enterprise.naming.java.javaURLContextFactory.getObjectInstance(javaURLContextFactory.java:32)
at javax.naming.spi.NamingManager.getURLObject(NamingManager.java:584)
at javax.naming.spi.NamingManager.getURLContext(NamingManager.java:533)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:279)
at javax.naming.InitialContext.lookup(InitialContext.java:351)
at gov.hud.pih.eiv.web.EjbClient.EjbClient.getUserManager(EjbClient.java:34)
【问题讨论】:
你能提供一个堆栈跟踪吗?代码是在容器外执行还是在容器内执行? 请也添加您的部署描述符。 部署描述符?我正在使用 netbeans 部署应用程序 ejb-jar.xml 文件,该文件位于 EJB 模块 jar 的 METAINF 目录中。 不,不在 Web 模块 (.war) 中,在 EJB-JAR 模块 (.jar) 中。您需要学习企业应用程序打包的基础知识(ear、ejb-jar、war)。 72.5.124.55/j2ee/1.4/docs/tutorial-update6/doc/… 【参考方案1】:我认为您想从 Sun Application Server 中的 Web 应用程序访问 EJB 应用程序(称为 EJB 模块),对吧?
好的,我们走吧。
当您将 EJB 部署到应用程序服务器中时,应用程序服务器会为其提供一个地址 - 称为全局 JNDI 地址 - 作为您访问它的一种方式(类似于您的地址)。它从一个应用程序服务器变为另一个。
在JBoss Application Server中,你可以在如下地址看到全局JNDI地址(启动后)
http://127.0.0.1:8080/jmx-console/htmlAdaptor
在 Sun Application Server 中,如果要查看全局 JNDI 地址(启动后),请执行以下操作
在以下地址访问管理控制台
http://127.0.0.1:4848/asadmin
然后点击JNDI浏览
如果您的 EJB 未在此处注册,则说明有问题
EJB 有两种形式:EJB 2.1 和 EJB 3.0。那么有什么区别呢?
嗯嗯嗯嗯……
让我们从 EJB 2.1 开始
-
创建主页界面
它定义了创建、销毁和查找本地或远程 EJB 对象的方法。它充当 EJB 对象的生命周期接口。所有主接口都必须扩展标准接口 javax.ejb.EJBHome - 如果您使用远程 ejb 对象 - 或 javax.ejb.EJBLocalHome - 如果您使用本地 EJB 对象。
// a remote EJB object - extends javax.ejb.EJBHome
// a local EJB object - extends javax.ejb.EJBLocalHome
public interface MyBeanRemoteHome extends javax.ejb.EJBHome
MyBeanRemote create() throws javax.ejb.CreateException, java.rmi.RemoteException;
Application Server 将创建 Home 对象作为您获取 EJB 对象的一种方式,仅此而已。
注意以下事项
会话 bean 的远程主接口必须定义一个或多个 create
方法。 无状态会话 bean 必须准确定义一个不带参数的 方法。
...
throws 子句必须包含 javax.ejb.CreateException
...
如果您的 Home 接口扩展 javax.ejb.EJBHome,则 throws 子句必须包含 java.rmi.RemoteException。如果它扩展了 javax.ejb.EJBLocalHome,则不得包含 java.rmi.RemoteException。
...
有状态会话 bean 的每个创建方法都必须命名为 create
,并且它 必须匹配会话中定义的 Init 方法或 ejbCreate 方法之一 豆类。匹配的 ejbCreate 方法必须具有相同的参数数量和类型。无状态会话 bean 的创建方法必须命名为 create,但不需要有匹配的“ejbCreate”方法。
现在创建一个业务接口,以便在我们的 EJB 对象中定义业务逻辑
// a remote EJB object - extends javax.ejb.EJBObject
// a local EJB object - extends javax.ejb.EJBLocalObject
public interface MyBeanRemote extends javax.ejb.EJBObject
void doSomething() throws java.rmi.RemoteException;
现在请注意以下事项
如果您使用远程 EJB 对象,远程接口方法不得公开本地接口类型或本地主接口类型。
...
如果您的 Home 接口扩展 javax.ejb.EJBObject,则 throws 子句必须包含 java.rmi.RemoteException。如果它扩展了 javax.ejb.EJBLocalObject,则不得包含 java.rmi.RemoteException。
现在我们的 EJB
public class MyBean implements javax.ejb.SessionBean
// why create method ? Take a special look at EJB Home details (above)
public void create()
System.out.println("create");
public void doSomething() throws java.rmi.RemoteException
// some code
;
现在请注意以下事项
它必须实现 javax.ejb.SessionBean。它定义了四种方法——上面未显示:setSessionContext、ejbRemove、ejbPassivate 和 ejbActivate。
注意我们的 bean 不实现我们的业务接口,因为 EJB 规范说:
对于接口中定义的每个方法,在会话 bean 的类中必须有一个匹配的方法。匹配方法必须有:
同名 相同数量和类型的参数,以及相同的返回类型。 会话匹配方法的 throws 子句中定义的所有异常 bean 类必须在本地接口方法的 throws 子句中定义。您必须根据
声明一个 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-instance" 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>br.com.MyBeanRemoteHome</home>
<remote>br.com.MyBeanRemote</remote>
<local-home>br.com.MyBeanLocalHome</local-home>
<local>br.com.MyBeanLocal</local>
<ejb-class>br.com.MyBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
</ejb-jar>
如果您没有本地 EJB 对象,请从上面的部署描述符中删除
<local-home>br.com.MyBeanLocalHome</local-home>
<local>br.com.MyBeanLocal</local>
如果您没有远程 EJB 对象,请从上面的部署描述符中删除
<home>br.com.MyBeanRemoteHome</home>
<remote>br.com.MyBeanRemote</remote>
并放入META-INF目录
我们的 jar 文件将包含以下内容
/META-INF/ejb-jar.xml
br.com.MyBean.class
br.com.MyBeanRemote.class
br.com.MyBeanRemoteHome.class
现在我们的 EJB 3.0
// or @Local
// You can not put @Remote and @Local at the same time
@Remote
public interface MyBean
void doSomething();
@Stateless
public class MyBeanStateless implements MyBean
public void doSomething()
没有别的,
在JBoss中放入jar文件
<JBOSS_HOME>/server/default/deploy
在 Sun Application Server 中访问(启动后)管理控制台
http://127.0.0.1:4848/asadmin
并访问 EJB 模块以部署您的 ejb-jar 文件
由于您在 NetBeans 中部署应用程序时遇到一些问题,我建议如下
-
创建一个简单的 Java 库 PROJECT(一个没有 main 方法的简单 jar)
无论您使用的是 JBoss,都将 /server/default/lib(包含 jar 文件以便您检索 EJB 的)jar 文件添加到您的 Java 应用程序(我不知道 Sun 应用程序服务器中的哪个目录)
上面的实现代码
现在创建另一个战争项目
-
添加我们刚刚在上面创建的项目并添加
并在您的 Servlet 或其他东西中实现以下代码,无论您使用的是 JBoss
public static Context getInitialContext() throws javax.naming.NamingException
Properties p = new Properties();
p.put(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory");
p.put(Context.URL_PKG_PREFIXES, " org.jboss.naming:org.jnp.interfaces");
p.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
return new javax.naming.InitialContext(p);
或者以下无论你是否使用 Sun Application Server - 将文件 appserv-rt.jar(我不知道 Sun Application Server 中哪个过去包含 appserv-rt.jar)放在你的类路径中
public static Context getInitialContext() throws javax.naming.NamingException
return new javax.naming.InitialContext();
为了在我们的 Servlet 或其他东西中访问您的 EJB
MyBeanRemote myBean = (MyBeanRemote) getInitialContext().lookup(<PUT_EJB_GLOBAL_ADDRESS_RIGHT_HERE>);
myBean.doSomething();
问候,
【讨论】:
你能看看这个问题吗? ***.com/questions/29190816/…【参考方案2】:最后两个答案都是正确的,因为它们是您需要更改/修复的东西。但是您看到的 NoSuchMethodError 不是来自您的代码,也不是来自试图找到您的代码的东西(我认为,如果是这种情况,会产生某种 NoClassDefFoundException)。这看起来更像是容器提供的 JNDI 提供者的不兼容版本,以及 Java 库中的 JNDI 实现想要什么。这是一个相当模糊的答案,但是,可以想象它可以通过升级您的应用程序服务器来解决,并且确保您不会在您的应用程序中部署与 JNDI 相关的基础设施类的可能陈旧的副本,这可能会造成干扰。
【讨论】:
【参考方案3】:首先,修复您的 web.xml 并在其中添加远程接口:
<ejb-ref>
<description>Sample EJB</description>
<ejb-ref-name>SampleBean</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<home>com.SampleHome</home>
<remote>com.Sample</remote> <!-- the remote interface goes here -->
</ejb-ref>
那么,关于java.lang.NoSuchMethodError
,Sean 是对的,您在 NetBeans 中使用的应用服务器“客户端库”版本与应用服务器版本(服务器端)不匹配。不过,我无法准确告诉您需要对齐哪些 JAR,请参阅 Sun 应用程序服务器文档。
PS:这不是问题的直接答案,但我认为您当前在使用调用 System.getProperties()
的结果创建初始上下文时没有传递任何有用的属性,这些没有任何帮助定义上下文环境的属性(例如初始上下文工厂)。有关详细信息,请参阅InitialContext javadocs。
【讨论】:
以上是关于ejb 查找失败并出现 NamingException的主要内容,如果未能解决你的问题,请参考以下文章
EJB Timer Service不可用,上下文取消部署失败