11

我在 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)
4

3 回答 3

37

我认为您想从 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 开始

  1. 创建主页界面

它定义了创建、销毁和查找本地或远程 EJB 对象的方法。它充当 EJB 对象的生命周期接口。所有 home 接口都必须扩展标准接口 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<METHOD> 方法。无状态会话 bean 必须准确定义一个没有参数的 <METHOD> 方法。

...

throws 子句必须包括 javax.ejb.CreateException

...

如果您的 Home 接口扩展 javax.ejb.EJBHome,则 throws 子句必须包含 java.rmi.RemoteException。如果它扩展 javax.ejb.EJBLocalHome,则不得包含 java.rmi.RemoteException。

...

有状态会话 bean 的每个创建方法必须命名为 create<METHOD>,并且它必须匹配会话 bean 类中定义的 Init 方法或 ejbCreate<METHOD> 方法之一。匹配的 ejbCreate<METHOD> 方法必须具有相同的参数数量和类型。无状态会话 bean 的 create 方法必须命名为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 的类中必须有一个匹配的方法。匹配方法必须有:

  • 同名
  • 相同数量和类型的参数,以及相同的返回类型。
  • 会话bean类的匹配方法的throws子句中定义的所有异常都必须在本地接口的方法的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 中部署应用程序时遇到一些问题,我建议如下

  1. 创建一个简单的Java库PROJECT(一个没有main方法的简单jar)
  2. 添加 /server/default/lib(包含 jar 文件,以便您检索 EJB 的)jar 文件到您的 Java 应用程序,无论您使用的是 JBoss(我不知道 Sun 应用程序服务器中的哪个目录)
  3. 实现上面的代码

现在创建另一个战争项目

  1. 添加我们刚刚在上面创建的项目并添加 <JBOSS_HOME>/client(包含 jar 文件以便访问我们的 EJB)。同样,我不知道 Sun Application Server 中的哪个目录。查看它的文档。
  2. 看它的全局映射地址如答案顶部所示

并在您的 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();

问候,

于 2009-09-30T05:54:49.910 回答
1

首先,修复您的 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 Application Server 文档。

PS:这不是问题的直接答案,但我认为您当前在使用调用结果创建初始上下文时没有传递任何有用的属性System.getProperties(),这些属性对定义环境没有任何帮助上下文(例如初始上下文工厂)。有关更多详细信息,请参阅InitialContext javadocs。

于 2009-09-24T21:03:27.507 回答
1

最后两个答案都是正确的,因为它们是您需要更改/修复的东西。但是您看到的 NoSuchMethodError 不是来自您的代码,也不是来自试图找到您的代码的东西(我认为,如果是这种情况,会产生某种 NoClassDefFoundException)。这看起来更像是容器提供的 JNDI 提供程序的不兼容版本,以及 Java 库中的 JNDI 实现想要什么。这是一个非常模糊的答案,但是,可以想象它可以通过升级您的应用程序服务器来解决,并且确保您没有使用您的应用程序部署与 JNDI 相关的基础设施类的可能陈旧的副本,这可能会造成干扰。

于 2009-09-25T03:37:33.500 回答