如果您把同一个 J2EE 应用程序部署到多个应用程序服务器上,而这些应用程序服务器共享一个 JNDI 名称空间,那么,由于名称空间中的 JNDI 名称必须是唯一的,这样做将会出现问题。部署到 WebSphere Application Server 环境中的 J2EE 应用程序,应该使用 java:comp/env 环境命名上下文(environment naming context(ENC))来查找 EJB,而不是使用 JNDI 名称来查找。有了这个命名上下文,就可以避免发生冲突,应用程序的可移植性也将好得多。
开发和部署按照 EJB 1.0 规范级别编写的 EJB,困难之一是处理 EJB home 的 JNDI 名称。例如,有很多代码写成像下面的代码片段(取自会话 bean)那样,试图查找 com.ibm.wsc.Bean2 EJB 的 home:
Context myInitCtx = new InitialContext();
Object result = myInitCtx.lookup("com/ibm/wsc/Bean2Home");
com.ibm.wsc.Bean2Home theBean2Home =(com.ibm.wsc.Bean2Home)
javax.rmi.PortableRemote.narrow(result,com.ibm.wsc.Bean2Home.class);
这一技术在Java开发环境(Java development tooling,JDT)中能工作得很好,在应用程序的部署阶段似乎也不出什么问题。只要看一下上面的代码,就可以确定在名称空间中赋给Bean2Home的JNDI名称,因为这个名称就是EJB Home接口名称。编码约定就跟 EJB 类名被用来构造定位 home 的代码那样相当简单。
当把“Bean2”部署到使用同一个(共享的) JNDI 名称空间的两个不同服务器中时,问题就冒出来了。
例如,有人可能有两台服务器,WSQASV 和 WSFXSV,它们共享同一个名称空间(即 LDAP 或 CosNaming 服务器),并且他想把同一个 J2EE 应用程序(即 .ear 文件)部署到这两台服务器中。由于每台服务器中的会话 bean 都必须查找/使用 Bean2Home 的正确实例,所以,这就出现了一个问题。要避免这个问题,必须做两件事:
安装在服务器 WSQASRV 中的 Bean2Home 的 JNDI 名称必须与安装在服务器 WSFXSV 中的 Bean2Home 的 JNDI 名称不同。这两个 JNDI 名称必须不同,EJB home 的 lookup( ) 才能把引用(即 IOR)返回给安装了该 EJB 的正确的服务器。
引用 Bean2Home 的客户机(即会话 bean)必须根据部署了该应用程序的服务器显式地指定 Bean2Home 的 JNDI 名称。
EJB 的命名模式已经开发,以硬编码的方式把 JNDI 名称编写到 java源代码中是问题的真正起因。我们需要这样一种能力,不必根据部署了 EJB 的服务器修改代码就能够提供特定于运行时的信息。结果是创建并实现一个模式,它利用 ResourceBundle 或 Property 文件提供运行时信息,如以下代码片段所示:
ResourceBundle myRB = ResourceBundle.getBundle("ServerProps");
String myBean2HomeJNDIName = myRB.getString("Bean2HomeName")
Context myInitCtx = new InitialContext();
Object result = myInitCtx.lookup(myBean2HomeJNDIName);
com.ibm.wsc.Bean2Home theBean2Home =(com.ibm.wsc.Bean2Home)
javax.rmi.PortableRemote.narrow(result,com.ibm.wsc.Bean2Home.class);
这一技术的全部要求就是为 WSQASV 服务器创建一个唯一的名为 ServerProps.properties 的 .properties 文件,WSQASV 服务器的这个文件包含有类似下面的内容:
Bean2HomeName=WSQASV/com/ibm/wsc/Bean2Home
WSFXSV 的 ServerProps.properties 文件包含有类似这样的内容:
Bean2HomeName=WSFXSV/com/ibm/wsc/Bean2Home
现在,我们有了一个模式,不管将 J2EE 应用程序部署到两台服务器中的哪一台,这个模式都不要求在部署之前对 java 代码作丝毫更改,EJB home 的命名约定得到了一定程度的保护,但受服务器限定。这个“服务器名”限定使得在任一台服务器中都可以正确定位 Bean2Home。在部署阶段,部署者只需要知道 .properties 文件的内容,以将正确的 JNDI 名指定给 EJB。
采用这种技术,只有一个问题还留待部署者去解决:如何管理特定于服务器的 .properties 文件。让人左右为难的是,.properties 文件既是特定于应用程序的(即应用程序中所包含的特定 EJB home 正在被查找),又是特定于服务器的(即 EJB home 的 JNDI 名称取决于安装了该应用程序的服务器)。问题是:ServerProps.properties 文件是在 J2EE 应用程序包(即 .ear 文件)中呢,还是在服务器的类路径中?把 .properties 文件放到 .ear 文件意味着 .ear 文件在部署到上述两台服务器之前必须先作修改。人们不希望这样做,原因与人们不希望修改 java 源代码的原因如出一辙。不过,人们倒是很希望有一个各个部件的单个包,而不必为特定于应用程序的文件具体配置服务器。
EJB 1.1 解决方案
幸运的是,EJB 1.1 规范引入了 JNDI 增强功能,特别是环境命名上下文(ENC)以及关于如何“找到” EJB、资源和特定于应用程序的环境变量的强烈推荐的做法。要了解详细信息,请参阅 EJB 1.1 规范的第 14 章和 J2EE 1.2 规范的第 5 章。以下代码片段使用所推荐的 java:comp/env 构造来查找 Bean2Home:
Context myInitCtx = new InitialContext();
Object result = myInitCtx.lookup("java:comp/env/ejb/Bean2Home");
com.ibm.wsc.Bean2Home theBean2Home =(com.ibm.wsc.Bean2Home)
javax.rmi.PortableRemote.narrow(result,com.ibm.wsc.Bean2Home.class);
如何把“java:comp/env/ejb/Bean2Home”字符串和驻留在某台特定服务器中的 Bean2Home 的 JNDI 名称关联起来,这项工作留给应用程序的装配者和部署者去做。应用程序开发者既不知道也不关心 Bean2Home 的 JNDI 名称。
特别地,装配者必须在引用 EJB 的 ejb-jar.xml 文件(或者是引用 servlet 的 web.xml 文件)中包含一条带有以下内容的子句:
ejb/Bean2Home
Entity
com.ibm.wsc.Bean2Home
com.ibm.wsc.Bean2
Bean2
.xml 文件的内容通常由开发工具(即 WebSphere Studio Application Developer)或装配工具(即应用程序装配工具(Application Assembly tool(AAT)))构建和验证,不要求手工构造。请注意,没有给出 JNDI 名称,只有一条声明,表明这个 EJB(或 servlet)将查找一个给定类型的 EJB home,并且该 EJB home 驻留在这个 J2EE 应用程序包即 .ear 文件中。(如果省略了 ejb-link 描述符,servlet 或 EJB 就可以查找并使用驻留在 JNDI 名称空间中具有这一 bean 类型的任何服务器中所驻留的 Bean2Home。)实际上,应用程序装配者并不知道也不关心 Bean2Home 的 JNDI 名称。JNDI 名称留给部署者指定,其限制条件是,不论 J2EE 应用程序被部署到什么服务器中,Bean2Home 都必须驻留在该 J2EE 应用程序中。
在把应用程序安装/部署到某一特定服务器(例如,在我们的示例中,是 WSQAEV 或 WSFXSV 服务器)中时,部署者必须做两件事:
为 Bean2Home 创建一个 JNDI 名称,它指向被安装到“这台”服务器的 Bean2Home。JNDI 名称在名称空间中必须是唯一的,这样才能够定位到驻留在“这台”服务器中的所期望的Bean2Home,而不至于无意中使用了驻留在别的服务器中的 Bean2Home。
把 EJB 引用解析为正确的 Bean2Home JNDI 名称。使用 ejb-link 描述符,这就迫使引用被解析为“这台”服务器中的 Bean2Home JNDI 名称。请注意,如果省略了 ejb-link,那么 ejb-ref 就有可能被解析为别的服务器中的另一个 Bean2Home 部署的 JNDI 名称。
要点是:应用程序(连带应用程序开发者)不需要知道在公共名称空间中注册的这台或任何其它服务器中所驻留的任何组件的实际 JNDI 名称。
应用程序可能不需要使用副文件就可以使用 EJB 的正确的 JNDI 名称,这取决部署组件的服务器。
不需要修改 J2EE 包(即 .ear 文件)中的文件或部署描述符。一个 .ear文件不经修改、不加调整就可以部署到任何服务器中。
这一技术大大增强了 EJB 的可移植性。很容易就可以部署应用程序,而不必为实际的 JNDI 名称劳心费神。可以从一个 J2EE 应用程序抽取出 EJB,然后很容易就可以将它集成到另一个 J2EE 应用程序中。
剩下的问题是:部署者应选择什么样的 JNDI 名称?要求是:
在部署 J2EE 应用程序的服务器的名称空间中,组件的 JNDI 名称应是唯一的。
命名模式如果不是自管理的,那就应该是易于管理的。
用于 WebSphere for z/OS 的 Systems Management Administration 工具允许部署者指定特选的 JNDI 名称,如果部署者选择这样做,或者应用程序要求这样做的话。当不使用 java:comp/env 技术进行 lookup( ) 的时候就会出现这种情况。更为重要的是,该管理工具允许部署者指定一个系统生成的名称,这样生成的名称必定是唯一的。名称的格式如下:
/////因此,如果 Bean2 驻留在 EntityBeans.jar 文件中,并且所有的 J2EE 组件都被打包到 BeanSalad.ear 中,.ear 文件将被部署到 WSFXSV 服务器中,这台服务器又在与 WSCPLEX sysplex 相关联的 WebSphere 节点/群集上,那么,所生成的名称将是:WSCPLEX/WSFXSV/BeanSalad/EntityBeans/Bean2/com.ibm.wsc.Bean2Home.class这个名称唯一地标识了驻留在位于节点 WSCPLEX 的 WSFXSV 服务器中的 Bean2Home,对比于驻留在位于这个节点的 WSQASV 服务器中的 Bean2Home。通过使用这一技术,我们实现了自管理的 JNDI 名称唯一性,这不为应用程序所知,并且应用程序的可移植性达