技术开发 频道

同时托管 J2EE 应用程序的多个版本

  通常有两种应用程序封装选择:

  将每个版本的 J2EE 应用程序中的所有 EJB 和 Web 模块封装成独立的自包含应用程序 EAR 文件,并且没有外部依赖性。 每个应用程序 EAR 文件可以单独地进行部署。在部署阶段,类加载冲突通过对不同的企业应用程序模块使用不同的应用程序类加载器得以解决。JNDI 名称空间冲突可以在应用程序装配阶段通过使用 描述符,并且使用无冲突的 JNDI 名而得以解决。servlet 路径冲突和外部资源冲突可以通过对 Web 应用程序的每个版本使用不同的上下文根而得以解决。尽管通过这种方式可以很简单地部署多个版本的应用程序,但是这种做法在组件模块改变时需要重新部署组件模块。图 9 显示了 EAR 文件的组成:一个 EJB JAR 文件( MyBankCMPEJB.jar )和一个 WAR 文件( MyBankCMPWeb.war )。这是一个自包含的应用程序,因为这个应用程序所需要的所有组件都包含在这个 .ear 文件中。所有其他的版本也要和这个 EAR 文件一样包含相同的文件。而且,多个版本的组件(例如 EJB Account)不能从公共的组件中访问,因为类名冲突在此情况中没有办法解决。因此,这种应用程序版本的粒度太大。

  图 9. MyBank 应用程序的自包含 EAR 文件的组成部分

  在同一个应用程序中混合使用不同版本的 EJB 和 Web 组件模块。通过这种方式,单个的模块可以独立地进行升级。Web 模块应用程序可以在不需要改动 EJB 模块的情况下进行升级,并且可以在不影响现有版本的情况下添加新版本的 EJB 模块。为了做到这一点,您必须将应用程序分成多个 .ear 文件。在我们的样本应用程序中,图 9 显示的 EAR 文件被分成下面几个部分:每个版本的 EJB 有一个 .ear 文件(请参见图 10 和 11)、每个版本的 Web 应用程序的 .ear 文件包含多个版本的 .war 文件、每个版本的 Web 应用程序(请参见图 12)。

  图 10 给出了 Account EJB 版本 1 的 .ear 文件。注意其中有两个 JAR 文件:

  MyBankCMPEJBv1 包含 Account EJB 版本 1 的特定接口和实现。

  MyBankCMPEJBCommonUtility 包含版本 1 和版本 2 中共用的接口和实现,以及 Transfer EJB,并且 Transfer EJB 在从版本 1 到版本 2 的变化中不会发生任何变化。

  类似的,图 11 给出了 Account EJB 版本 2 的 .ear 的组成。相同的 .jar 文件 MyBankCMPEJBCommonUtility 被封装到 MyBankCMPEJB [v1|v2] EAR 的两个版本中。

  图 12 给出了 Web .ear 文件的组成,以及 MyBankCMPWebv1.war 和 MyBankCMPWebv2.war (包括特定于版本的 CreateAccount servlet)和 MyBankCMPWebCommon (包括和版本无关的 TransferFunds servlet)。

  图 10. 应用程序 EAR EJB 版本 1 的组成

  图 11. 应用程序 EAR EJB 版本 2 的组成

  图 12. Web EAR 的组成

  通过这种方法拆分应用程序可以使不同版本的 EJB 组件隔离开来,这种隔离是通过使用不同的应用程序类加载器实现的,一个 EAR 文件对应一个类加载器。不同版本的 Web 组件模块通过不同的 WAR 类加载器而隔离开来,一个 Web 模块对应一个 WAR 类加载器。由于 WAR 类加载器是应用程序类加载器的子类,所以所有版本的 Web 模块都可以封装在同一个企业应用程序中。为了使应用程序类加载器或 Web 类加载器可以加载通用的实用程序类 JAR 文件,就必须在类路径头部指定这些 JAR 文件依赖于 EJB JAR 或 WAR 清单文件(manifest file)。样本 7 给出了 MyBankCMPEJBv1.jar 中的清单文件的例子;样本 8 给出了 MyBankCMPWebv1.war 中的清单文件的例子。

  样本 7. MyBankCMPEJBv1.jar 中用于指定相关 JAR 文件的清单文件  

1 Manifest-Version: 1.0
2 Class-Path:  MyBankCMPEJBCommonUtility.jar

         样本 8. MyBankCMPWebv1.war 中用于指定相关 JAR 文件的清单文件

1 Manifest-Version: 1.0
2 Class-Path: MyBankCMPEJBCommonUtility.jar MyBankCMPEJBv1Utility.jar My
3 BankCMPWebCommonUtil.jar

  图 13. 在 WebSphere 应用程序服务器 V5 中配置共享类库

 

  为了使 Web 应用程序能够调用 EJB JAR 组件,需要将 Web 应用程序中使用的 java:comp/env EJB 引用绑定到适当版本的 EJB 本地接口的 JNDI 名。如果 Web 应用程序组件和 EJB 组件通过不同的类加载器来加载,那么 EJB 组件的本地接口是不能使用的。您必须使 EJB 远程接口的客户端类对应用程序类加载器可用。这可以通过两种方式来得以实现:

  EJB 远程接口客户端类可以作为实用程序 JAR 文件封装到 Web EAR 文件中,并且可以通过修改用于每个 Web 应用程序 WAR 文件的清单文件,在类路径头部下面添加 EJB 客户端类实用程序 JAR 文件。(请参见样本 8)。

  将 EJB JAR 作为共享的类库添加到 Web WAR EAR 应用程序中。

  跟踪分布式组件的变化

  当将多个版本的 J2EE 应用程序组件部署到同一个 WebSphere 域中时,为了安全起见,应该进行一些运行时检查。另外,保留对部署模块版本变化的跟踪记录也是一种可行的做法。 Java Product Versioning Specification 将 Java 包定义为一个可以开发、封装、验证、升级及分布式的一致性单元。JAR 文件的清单文件(manifest file)包含指定包版本的属性。样本 9 给出了在清单文件中指定 J2EE 应用程序组件版本的例子。在运行时,J2EE 组件(包含在一个包中)的版本可以从 java.lang.Package 接口得到。样本 10 给出了获得在清单文件中指定的版本代码的例子。包的版本信息可以在运行时用来检查分布式应用程序组件的兼容性。例如,根据 Java 版本规范可以从 EJB JAR 清单文件中取得 EJB 的版本信息。客户端的版本信息可以通过客户端 JAR 文件获得,服务器端版本信息可以从服务器端 JAR 文件获得,并且通过 EJB 组件的远程接口来查询,从而可以在运行时检查版本的兼容性。

  样本 9. 在 EJB JAR 清单文件中指定的包版本信息

1 Manifest-Version: 1.0
2 Name: com/ibm/mybank/ejb/v2/
3 Specification-Title: "EJB"
4 Specification-Vendor: "Sun Microsystems, Inc.".
5 Specification-Version: "2.0"
6 Implementation-Title: "MyBank EJBs"
7 Implementation-Vendor: "IBM"
8 Implementation-Version: "1.4"

  样本 10. 从 JAR 清单文件中获得包版本的应用程序代码

1 public String getImplVersion() {
2         Package p = this.getClass().getPackage();
3         String specTitle = p.getSpecificationTitle();
4         String specVersion = p.getSpecificationVersion();
5         String implTitle = p.getImplementationTitle();
6         String implVersion = p.getImplementationVersion();
7         String messageLine = "Server Specification: " + specTitle +
8                                  ", specification version: " +
9                                  specVersion +
10                              ", Implementation: " + implTitle +  
11                                  ", implementation version: " +
12                                  implVersion + "\n";        
13         return messageLine;
14     }
15

  会话对象的不兼容性

  Java 产品版本控制规范(Java Product Versioning Specification)讨论了可以对可串行化类做出哪些改变,或者不可以作出哪些改变,以保持其和以前版本的兼容性。对会话对象类的改变也是要遵循相同的法则。另外,自定义的 readObject 和 writeObject 方法可以加到该类的各个版本中。

  结束语

  最近,应用程序的版本问题引起了广泛的注意。对待版本问题的传统做法往往是轻率地使用“大手笔”的方法使应用程序从一个版本转变到另外一个版本,然而,也可以在较小粒度的水平上进行增量升级,获得使 J2EE 组件的不同版本得以共存。本文提出了在满足同时托管 J2EE 组件的多个版本的要求时所面临的挑战,并且提供了一些方法(既考虑到了部署阶段又考虑到了设计阶段)来帮助您解决这些问题。

0
相关文章