【IT168 技术文章】
本文介绍了将 J2EE 应用程序从不同平台移植到 WebSphere 应用服务器上的共同方法和常见的问题.
概述
Java Classloader长期以来一直是导致混乱的根源,并且随着 Java 语言的发展变得比以往任何时候都更为复杂。随着 J2EE 应用服务器的出现,Java Classloader的复杂性进一步增加了。现在,JVM 中的每个应用程序都可能有自己的Classloader层次,这将导致一个单独的 JVM 可能包含许多的Classloader。而不同的J2EE应用服务器的Classloader的层次和策略也会有所差异,移植的复杂度也随之上升。
第一部分曾经提到:在移植的前期,我们应当分析系统的框架,澄清其中各个模块之间的依赖关系(包括各个业务模块之间的依赖关系,以及Web模块和EJB模块之间的依赖关系等),为了尽量避免模块之间的交叉引用,我们甚至要重新打包。大家可能会问,我们的应用程序原本在WebLogic 、Tomcat、Jboss、Resin上能够正常的运行,为什么我们要重新分析模块之间的依赖关系,甚至重新打包呢?实际上,每个应用服务器都有着对于ClassLoader的不同实现。由于这些ClassLoader在装载类文件时的行为会有所差异,所以如果应用程序未经重整和优化,很有可能在WebSphere应用服务器上运行失败。然而,面临这种差异,我们并不需要过多的恐慌。实际上,只要把握以下几个原则,相信,交织在模块依赖和类型装载之中的问题,就可以迎刃而解了:
一、 理解WebSphere ClassLoader的装载层次和装载策略
二、 理清模块间的依赖关系
三、 将合适的装载策略应用到各个模块
注意:我们并不需要了解WebLogic、Tomcat、JBoss、Resin等J2EE应用服务器的 Classloader的体系结构,只要我们理解了WebSphere的Classloader的体系结构,理清了应用程序的各个模块之间的依赖关系,就可以解决由不同的J2EE应用服务器的Classloader的体系结构的差异给移植带来的问题。
WebSphere ClassLoader体系结构
首先我们简单介绍一下WebSphere ClassLoader的体系结构,详细内容可参看参考文档。
图一、WebSphere Classloader层次结构图
处于体系结构最上层的是系统 Classloader,它由bootstrap,extensions和 classpath三个classloader组成,bootstrap classloader会查找jre/lib下的类文件,从而加载核心类库,extensions classloader使用系统属性java.ext.dirs(通常是jre/lib/ext)查找和加载类文件,classpath classloader使用操作系统的classpath环境变量来查找和加载类文件。
处于体系结构第二层的是WebSphere Extensions Classloader,它被用于装载WebSphere的运行时类库、J2EE类库以及用户代码。它使用系统属性ws.ext.dirs(通常是%was_root%\classes,%was_root%\lib和%was_root%\lib\ext)查找和加载类文件。
处于体系结构第三层的是Application Classloader,用于加载EARs,RARs,JARs中的类文件。由于Application Classloader Policy是MULTIPLE,WebSphere应用服务器会为每一个EAR文件(EAR 1到EAR N)分配了一个Application Classloader。值得注意的是,如果WAR Classloader Policy如果设置为Application,那么Application Classloader可用于加载WARs中的类文件。
处于体系结构最底层的是WAR Classloader,用于加载WAR文件中的类文件。图中示意了WebSphere应用服务器为每一个WAR文件(WAR 1到 WAR N)分配了一个WAR Classloader的场景。值得注意的是,如果WAR Classloader Policy设置为MODULE,WebSphere应用服务器才会使用WAR Classloader加载WAR文件中的类文件。
图一中的单向箭头表明了引用次序,即处于下面的Classloader可以调用其上层的类文件,而上层的Classloader无法调用其下面的类文件。这就为应用程序及其各个模块的组织结构和设置Classloader策略提供了线索和限制。