如何在was中解决jar包冲突.docx

上传人:b****7 文档编号:8910290 上传时间:2023-02-02 格式:DOCX 页数:17 大小:582.44KB
下载 相关 举报
如何在was中解决jar包冲突.docx_第1页
第1页 / 共17页
如何在was中解决jar包冲突.docx_第2页
第2页 / 共17页
如何在was中解决jar包冲突.docx_第3页
第3页 / 共17页
如何在was中解决jar包冲突.docx_第4页
第4页 / 共17页
如何在was中解决jar包冲突.docx_第5页
第5页 / 共17页
点击查看更多>>
下载资源
资源描述

如何在was中解决jar包冲突.docx

《如何在was中解决jar包冲突.docx》由会员分享,可在线阅读,更多相关《如何在was中解决jar包冲突.docx(17页珍藏版)》请在冰豆网上搜索。

如何在was中解决jar包冲突.docx

如何在was中解决jar包冲突

如何在was中解决jar包冲突

大型的基于WebSphere的项目开发中,同一个WebSphereApplicationServer(以下简称WAS)上会部署多个应用程序,而这多个应用程序必然会共用一些jar包,包括第三方提供的工具和项目内部的公共jar等。

把这些共用的jar包提取出来在多个应用程序之间共享,不仅可以统一对这些jar包进行维护,同时也提高了WAS的性能。

但是随着应用的不断扩大,新的应用程序的不断增加,新的应用程序会希望使用一些更高版本的共享jar包,而由于系统运行维护的需要,老的应用程序仍然希望用老版本的共享jar包,这样就必然造成了共享jar包的版本冲突。

jar包版本冲突问题是在大型应用项目的开发中经常遇到的问题,本文试图从WebSphere的类加载器入手,讨论几种在不同情况下解决jar包冲突问题的办法。

WebSphere中类加载器介绍

Jar包冲突实际上是应用程序运行时不能找到真正所需要的类,而影响类的查找和加载的是JVM以及WebSphere中的类加载器(classloader),为此,我们首先介绍一下WebSphere中的类加载器以及一些相关的概念。

WebSphere中类加载器层次结构

Java应用程序运行时,在class执行和被访问之前,它必须通过类加载器加载使之有效,类加载器是JVM代码的一部分,负责在JVM虚拟机中查找和加载所有的Java类和本地的lib库。

类加载器的不同配置影响到应用程序部署到应用程序服务器上运行时的行为。

JVM和WebSphere应用程序服务器提供了多种不同的类加载器配置,形成一个具有父子关系的分层结构。

WebSphere中类加载器的层次结构图1所示:

图1:

WebSphere中类加载器的层次结构

 

如上图所示,WebSphere中类加载器被组织成一个自上而下的层次结构,最上层是系统的运行环境JVM,最下层是具体的应用程序,上下层之间形成父子关系。

∙JVMClassloader:

位于整个层次结构的最上层,它是整个类加载器层次结构的根,因此它没有父类加载器。

这个类加载器负责加载JVM类,JVM扩展类,以及定义在classpath环境变量上的所有的Java类。

∙WebSphereExtensionsClassloader:

WebSphere扩展类加载器,它将加载WebSphere的一些runtime类,资源适配器类等。

∙WebSpherelib/appClassloader:

WebSphere服务器类加载器,它将加载WebSphere安装目录下$(WAS_HOME)/lib/app路径上的类。

在WASv4版本中,WAS使用这个路径在所有的应用程序之间共享jar包。

从WASv5开始,共享库功能提供了一种更好的方式,因此,这个类加载器主要用于一些原有的系统的兼容。

∙WebSphere"server"Classloader:

WebSphere应用服务器类加载器。

它定义在这个服务器上的所有的应用程序之间共享的类。

WASv5中有了共享库的概念之后,可以为应用服务器定义多个与共享库相关联的类加载器,他们按照定义的先后顺序形成父子关系。

∙ApplicationModuleClassLoader:

应用程序类加载器,位于层次结构的最后一层,用于加载J2EE应用程序。

根据应用程序的类加载策略的不同,还可以为Web模块定义自己的类加载器。

关于WebSphere的类加载器的层次结构,以下的几点说明可能更有助于进一步的理解类的查找和加载过程:

∙每个类加载器负责在自身定义的类路径上进行查找和加载类。

∙一个子类加载器能够委托它的父类加载器查找和加载类,一个加载类的请求会从子类加载器发送到父类加载器,但是从来不会从父类加载器发送到子类加载器。

∙一旦一个类被成功加载,JVM会缓存这个类直至其生命周期结束,并把它和相应的类加载器关联在一起,这意味着不同的类加载器可以加载相同名字的类。

∙如果一个加载的类依赖于另一个或一些类,那么这些被依赖的类必须存在于这个类的类加载器查找路径上,或者父类加载器查找路径上。

∙如果一个类加载器以及它所有的父类加载器都无法找到所需的类,系统就会抛出ClassNotFoundExecption异常或者NoClassDefFoundError的错误。

类加载器的委托模式

类加载器有一个重要的属性:

委托模式(DelegationMode,有时也称为加载方式:

Classloadermode)。

委托模式决定了类加载器在查找一个类的时候,是先查找类加载器自身指定的类路径还是先查找父类加载器上的类路径。

类加载器的委托模式有两个取值:

∙Parent_First:

在加载类的时候,在从类加载器自身的类路径上查找加载类之前,首先尝试在父类加载器的类路径上查找和加载类。

∙Parent_Last:

在加载类的时候,首先尝试从自己的类路径上查找加载类,在找不到的情况下,再尝试父类加载器类路径。

有了委托模式的概念,我们可以更加灵活的配置在类加载器的层次结构中类的加载和查找方式。

表1中给出了在WebSphere的类加载器层次结构中各个类加载器的委托模式的定义,并给出了不同的类加载器内类的生命周期。

注意:

在上表中,"JVMClassloader"因为在类加载器的最顶层,它没有父类加载器,因此其委托模式为N/A,"WebSphereExtensionsClassloader"和"WebSpherelib/appClassloader"的委托模式固定为表中的取值,不可配置,其它的类加载器的委托模式都是可以配置的。

WebSphere中的类加载器策略

WebSphere中对类加载器有一些相关的配置,称为类加载器策略(classloaderpolicy)。

类加载器策略指类加载器的独立策略(classloaderisolationpolicy),通过类加载器策略设置,我们可以为WAS和应用程序的类加载器进行独立定义。

每个WAS可以配置自己的应用程序类加载器策略,WAS中的每个应用程序也可以配置自己的Web模块类加载器策略,下面我们对这两种策略分别介绍。

1.应用服务器(WAS)配置:

应用程序类加载器策略

应用服务器对应用程序类加载器策略有两种配置:

∙Single:

整个应用服务器上的所有应用程序使用同一个类加载器。

在这种配置下,每个应用程序不再有自己的类加载器。

∙Multiple:

应用服务器上的每个应用程序使用自己的类加载器。

2.应用程序配置:

Web模块类加载器策略

应用程序中对Web模块类加载器有两种配置:

∙Application:

整个应用程序内的所有的实用程序jar包和Web模块使用同一个类加载器。

∙Module:

应用程序内的每个Web模块使用自己的类加载器。

应用程序的类加载器仍然存在,负责加载应用程序中Web模块以外的其它类,包括所有的实用程序jar包。

从上面的定义可以看出,不同的类加载器策略的配置下,类加载器的层次结构上的某些类加载器可能不存在。

比如在应用程序服务器的应用程序类加载器策略定义为single的情况下,应用程序的类加载器将不存在,同一个应用服务器上的所有应用程序将共用同一个类加载器,这也就意味着不同的应用程序之间的类是共享的,应用程序间不能存在同名的类。

在WebSphere中解决jar包冲突

Jar包冲突问题实际上就是应用程序希望用某一个确定版本的jar包中的类,但是类加载器却找到并加载了另外一个版本的jar包中的类。

在上一部分介绍了WebSphere中类加载器的基本概念和相关配置之后,我们来看如何在WebSphere中解决jar包冲突。

在WASv5版本之前,使用共享jar包的方式是将jar包放在$(WAS_HOME)/lib/app路径下,从上一部分中,我们可以看到,这个路径正是"WebSpherelib/appClassloader"类加载器的类查找路径,WebSphere会查找这个路径以取得相应得jar包中的Java类,从而做到在WebSphereND上的多个应用程序之间共享jar包的目的。

但是这样做的一个缺点就是这些共享jar包暴露给WebSphereND上所有的应用程序,对于那些希望使用jar包其它版本的应用程序,这些jar包也同样存在在了它们的类加载器类路径上,因此,就不可避免的会造成版本的冲突。

在WASv5版本及之后,增加了共享库(sharedlibrary)的概念,推荐的在多个应用程序间共享jar包并避免jar包冲突的方式是使用共享库。

具体分析引起jar包冲突的情况,主要有三种:

∙多个应用程序间jar包冲突:

多个应用程序间由于使用了共享jar包的不同版本而造成jar包版本冲突。

∙应用程序中多个Web模块间jar包冲突:

同一个应用程序内部,不同的Web模块间同时使用一个jar包的不同版本而造成jar包版本冲突。

∙应用程序中同一个Web模块内jar包冲突:

同一个应用程序内部,同一个Web模块内,由于需要同时使用同一个jar包的两个版本而造成的jar包冲突

本部分根据这三种jar包冲突的情况,讨论三种解决jar包冲突的办法,并具体讨论三种解决办法的实现步骤和适用情况:

∙共享库方式解决jar包冲突:

主要解决应用程序间的jar包冲突问题

∙打包到Web模块中解决jar包冲突:

主要解决应用程序中多个Web模块间jar包冲突问题

∙命令行运行方式解决jar包冲突:

主要解决应用程序中同一个Web模块内jar包冲突问题

共享库方式解决jar包冲突

在WASv5中,提供了一种很好的机制,使得jar包只存在于需要这个jar包的应用程序的类加载器的路径上,而其它的应用程序不受它的任何影响,这就是共享库(Sharedlibrary)。

共享库可以用在应用服务器级别和应用程序级别,使用应用程序级别的共享库,其好处就是在不同的应用程序之间使用共享jar包的不同版本。

我们可以为一些通用jar包的每个不同版本定义成不同的共享库,应用程序希望使用哪个版本,就把这个版本的共享库放到应用程序的类加载器的类路径上,这种方式有效的解决了应用程序之间jar包冲突的问题。

下面举例介绍定义和使用共享库的具体方法,本例中,假设存在xerces.jar包版本冲突。

1.定义共享库

系统管理员可以在WebSphere的Adminconsole中定义共享库,可以分别在Cell、Node以及server的级别上定义。

∙步骤一:

进入Adminconsole,选择Environment>SharedLibrary>new。

如图2所示:

图2:

WebSphereAdminConsole中进入共享库页面

∙步骤二:

给出共享库的名字,并指定共享的文件和目录。

多个不同的文件/目录之间通过"Enter"键分隔,且不能有路径分隔符,如":

"和";"等。

如图3所示:

图3:

WebSphereAdminConsole中添加共享库

∙步骤三:

点击Apply或者OK之后,就添加了一个名字为XercesV2.0的共享库。

记住添加完成后一定要在adminconsole保存配置。

如图4所示:

图4:

WebSphereAdminConsole中共享库列表

2.安装应用程序

进入Adminconsole,选择Applications>InstallNewApplication安装应用程序。

请参照IBMWebSphere的Adminconsole使用手册进行安装新的应用程序,此处不再详细介绍。

3.将共享库关联到应用程序

∙步骤一:

进入Adminconsole,选择Applications>Enterpriseapplications,并选择需要使用共享库的应用程序。

注意:

因为要改变应用程序的设置,所以如果应用程序已经运行,需要先停掉应用程序。

如图5所示:

图5:

WebSphereAdminConsole中选择需要配置的应用程序

∙步骤二:

点击应用程序,进入后,选择Libraries。

如图6所示:

图6:

WebSphereAdminConsole中选择应用程序库属性

∙步骤三:

点击Add,为应用程序添加共享库。

如图7所示:

图7:

WebSphereAdminConsole中应用程序添加库

∙步骤四:

从下拉列表中选择所需要的共享库,点击OK。

如图8所示:

图8:

WebSphereAdminConsole中应用程序添加库页面指定所用的共享库

这样,XercesV2.0共享库定义的xerces版本就存在于了应用程序类加载器的类加载路径上。

注意,在添加完成后要保存服务器的设置。

4.设置应用程序的类加载器的委托模式为Parent_Last

为了进一步防止共享库定义的jar包的其它版本已经存在于JVM或者WebSphere的类加载器路径上,还需要设置应用程序的类加载器的委托方式为Parent_Last。

∙步骤一:

进入Adminconsole,选择Applications>Enterpriseapplications>,选择需要配置的应用程序。

如图9所示:

图9:

WebSphereAdminConsole中选择需要配置的应用程序

∙步骤二:

点击进入应用程序,设置类加载器的委托模式为Parent_Last。

注意:

在配置完成后,要保存配置,最后启动应用程序。

如图10所示:

图10:

WebSphereAdminConsole中为应用程序设置类加载器委托模式

通过上面的配置,即使xerces的其它版本已经存在于系统中,应用程序在运行时,其类加载器也会首先查找并加载指定的共享库中的xerces版本。

这样我们就通过使用共享库的方式,解决了jar包版本冲突问题。

打包到Web模块中解决jar包冲突

共享库的方式,只是在应用程序的层次上,在多个应用程序之间解决了共享jar包造成的版本冲突问题,如果一个应用程序的内部,其中一个Web模块使用了一个jar包的A版本,而另一个Web模块使用这个jar包的B版本,在这种情况下造成的jar包冲突,共享库的方式是无法解决的,我们可以考虑将其中一个在多个应用程序间共享的jar包版本,比如A版本,定义成共享库,或者放在"WebSpherelib/appClassloader"类加载器路径上供多个应用程序使用,而将B版本的jar包打包到使用它的Web模块中的方式来解决冲突。

其次,目前很多在线的系统是WASv4的遗留系统,其上运行的应用程序已经使用了"WebSpherelib/appClassloader"类加载器,将jar包放在$(WAS_HOME)/lib/app目录下进行共享。

如果由于其中某个应用程序的升级或者新增加某个应用程序,需要使用某个共享jar包的其它版本,在这种情况下,为了减少对系统的影响,也可以考虑将这个共享jar包的新版本打包到升级(或新增)的应用程序中的方式来解决jar包冲突。

由于Web模块的WebContent/WEB-INFO/lib目录在应用程序Web模块的类加载器查找路径上,因此,我们可以把jar包放在这个目录下,Web模块的类加载器将自动查找并加载这个jar包中的类。

∙步骤一:

在WSADIE集成开发环境中,将冲突jar包放在Web模块的WebContent/WEB-INFO/lib目录下。

如图11所示:

图11:

WSADIE中为Web模块添加库

∙步骤二:

在Adminconsole中,将应用程序部署到WebSphereserver上之后,进入Applications>EnterpriseApplications,选择相应的应用程序,并确认应用程序不在运行状态(参见前面章节中选择应用程序的步骤)。

点击进入应用程序,确认应用程序的类加载器的委托模式为Parent_First,应用程序的类加载器策略为Module。

如图12所示:

图12:

WebSphereAdminConsole中应用程序属性配置页面

∙步骤三:

在同一个页面上,选择WebModules,点击进入。

如图13所示:

图13:

WebSphereAdminConsole中选择应用程序Web模块属性

∙步骤四:

点击相应的包含冲突jar包的Web模块,设置Web模块的类加载器的委托模式为Parent_Last。

注意:

在设置完成后要保存服务器配置,并启动应用程序。

如图14所示:

 图14:

WebSphereAdminConsole中为Web模块指定类加载器委托模式

将冲突jar包打包到Web模块中,并设置相应Web模块的类加载器的委托模式为Parent_Last,应用程序在运行过程中加载类的时候,这个Web模块的类加载器会首先查找WebContent/WEB-INFO/lib目录下的jar包进行类的加载;而对于其它的Web模块,由于其类加载器的委托模式仍然为缺省的Parent_First,它们的类加载器仍然首先从应用程序的共享库或者WebSphere的共享路径上加载jar包中的类,从而解决了jar包冲突的问题。

命令行运行方式解决jar包冲突

不论是设置共享库,还是将冲突jar包打包到应用程序中,其解决的问题都是在应用程序的一个Web模块中只使用了冲突jar包的一个版本的情况。

我们在开发中曾经遇到过这样的情况:

应用程序的Web模块中已经使用了1.4版本的xerces.jar,由于Web功能的扩展,在这个模块中又引入一个新的第三方工具,而这个第三方工具需要使用2.0版本的xerces.jar才能正常工作,这种情况下的jar包冲突如何解决呢?

在前面类加载器的部分已经介绍过,每个应用程序的一个Web模块最多只能有一个类加载器,而Web模块的类加载器中加载的类的生命周期为整个应用程序的运行期,也就是说,Web模块加载器不可能同时加载一个类的两个版本,同时,Web模块的类加载器的委托模式也是在应用程序运行前设置的,在应用程序运行期内无法改变的,因此,上面描述的在一个Web模块中同时使用两个版本的jar包的问题,象前两种方法那样配置运行在一个JVM内的类加载器的设置的方法是无法解决的。

唯一的解决办法就是在应用程序运行的JVM外,启动另外一个JVM来运行调用冲突jar包的代码,因为两个不同的JVM可以加载各自的类,从而解决jar包冲突问题。

这种情况下,原来使用jar包的老版本的方式(包括jar包放置路径,共享库设置方式,类加载器的委托模式等)不变,将对jar包新版本的调用通过命令行运行方式实现。

具体做法是:

将对jar包新版本内功能的调用,封装到一个可以单独运行的类中,在Web模块中以命令行方式运行这个类。

同时把这个类以及jar包的新版本放在任意一个was可访问的路径上(比如/usr/WebSphere),在命令行的classpath参数中包含这个路径(比如/usr/WebSphere)。

下面通过举例说明命令行运行方式的编程过程,在本例中,假设TestEar应用程序的Web模块TestWar中,已经使用了conflict_v1.jar,由于新添功能需要使用conflict_v2.jar中的exampleCall()功能。

冲突jar包conflict_v2.jar提供的功能:

代码1:

冲突jar包conflict_v2.jar功能

Package;

PublicclassConflictClass{

…….

PublicstaticStringexampleCall(stringparam){

Stringrs;

……;

Returnrs;

}

……

}

不存在冲突问题时的编码举例:

如果没有jar包冲突问题,则对这个功能的调用是简单的,只需要将conflict_v2.jar放在应用程序自身或者其父类加载器的查找路径上,然后在Web模块中直接调用即可,如下:

代码2:

不存在冲突时的调用方式

PublicStringmethodA(Stringparam){

……

Stringrs=ConflictClass.exampleCall(param);

……

Returnrs;

}

存在冲突后的命令行运行方式编码举例

针对jar包冲突问题,我们需要在Web模块中做如下的修改:

∙步骤一:

将冲突jar包放在was可访问的路径上,比如/usr/WebSphere/conflict_v2.jar。

∙步骤二:

将对包含冲突代码的调用封装到一组可单独运行的类中,它们将调用冲突jar包的功能,并将结果以系统输出的方式打印到系统标准输出上。

将这些类封装到一个单独的jar文件中,比如workAroundConflict.jar,并将其放在was可访问的路径上,比如/usr/WebSphere/workAroundConflict.jar。

Package;

Import;

PublicclassWorkAround{

Publicstaticvoidmain(String[]args){

Stringparam1=args[0];

StringreturnStr=ConflictClass.exampleCall();

""+returnStr+"");

Return;

}

}

代码3:

将对冲突代码的调用写入一个单独的类WorkAround

∙步骤三:

在Web模块中通过命令行方式调用封装的类,通过classpath指定所有依赖的jar包和类路径。

运行封装类,从系统标准输出中取得运行结果。

PublicstaticStringmethodA(Stringparam){

……

StringrtStr="";

StringlStr="";

StringrStr="";

//putallthedependencyjarhere

StringclassPath=

"/usr/WebSphere/conflict_v2.jar;

/usr/We

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 考试认证 > 其它考试

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1