为什么同一server两个war包调用同一ejb home接口会出现错误? (200分)

  • 主题发起人 主题发起人 roychen
  • 开始时间 开始时间
R

roychen

Unregistered / Unconfirmed
GUEST, unregistred user!
大家好,我在用j2ee平台开发一个软件时碰到这么一个问题:我在web server端有2个war包,
这两个war包都要用到ejb server端的一个ejb接口。但是当这两个war包分别去远程取这个ejb
home 接口时,第二个war包的调用就会出现 ClassCastException。
调用是这样写的:
Context initial = getInitialContext();
Object objref = initial.lookup(JNDINames.EJB_HOME);
EjbHome home = (EjbHome) PortableRemoteObject.narrow(objref,
EjbHome.class);
两个war包的调用程序一摸一样,而且不管先调用哪个,总是在第二个调用的时候出错。
单步跟踪到第3句,narrow里面就抛出ClassCastException。
有没有哪位高手知道这个问题,请帮忙解决一下,万分感谢
 
你用的appserver是什么呀?
 
appserver是weblogic7.0。
奇怪的是,如果我把两个war包分别放在两个web server上来,调用就不会出错。
不管是resin,tomcat都是这种情况。
 
我很久没写过ejb了,也看不出有什么问题,但有一点很不解,
所谓narrow,是提供一个安全的向下造型的手段,而这里你要
做的其实只是一个向上造型,是不是代码有问题?
 
sorry,查了一下资料,你的写法是正确的.:(
我没有用过weblogic.
你可以把抛出的异常堆栈贴出来看看吗?如果是类型错误,那么应该可以看出
是由何种类型向何种类型转换时出错的.
 
谢谢小猪。
这个错误奇怪的地方:
如果只有一个war包,都是正确的。
刚开始以为是classload不对。
但当有两个war包的时候,我单步跟踪进去,
在类型转换前,我把classload都检查了一遍,居然都是对的。
真有点想不通,:(。
也许是weblogic的bug,说不清楚
 
to:小猪
好久不见,不写EJB了??现做什么啊。。。。
to:roychen
你遇到情况很怪,只能试着一句屏掉再试,
 
是啊,好怪啊。我又做了两个实验
我把一个war包复制了一份,放在同一个server下,那么两个war包是一摸一样的,
运行结果还是一样,第二个出错了。
后来我把servlet engine也改成用weblogic,前后都是weblogic,结果正确了。
只能说weblogic与 tomcat、resin的兼容性有问题了。
 
一个包时没问题,两个包就有事,是不是有这可能,一个包调用时,把资源锁定了,另一个包也就要待一个包退出才能用
但这个包的退出却没有释放啊,具体再看程序了
 
应该不是这个原因。这两个war包在web server端是没有什么资源共享的。
有共享的也只能在appserver端。
而这个错误是在web server端抛出的,appserver端并没有错误
 
it depends on the implementation of [:)]classloader[:)] in appserver.
 
xiangya,你好。你能说的详细一点吗?这和appserver端的classload有什么关系?
 
建议:
1,如果你真想了解classloader的机制的话,你可以参考sun的j2eeRI或者jboss和enhydra的公码(公开源代码opensource:) )。
2,发布两个完全一样的war是没有任何意义的,即使能够发布出去,实际上应该说是appserver实现的一个错误设计。
3,认真看了一下你的问题,也许这些东西不能满足你的需要。我想你应该将weblogic的log功能开到最详细,此外还可以在ejb上加上log,
weblogic使用log4j。然后贴上来看看。
下面是一些闲聊,仅供参考。
(来源:websphere)本身不允许拥有相同的context 目录的Web modules安装在同一个虚拟主机上。在 beta 版中不会检测在同一个虚拟主机上不同Web modules是否有相同的context目录。但是在GA版中会检测 同时不允许这种情况的存在
(来源:j2ee部署)
一个WAR文件包含一个Web应用。EAR文件可以包含多个Web应用,EAR文件中的每个Web应用必须有一个唯一的部署上下文。EAR文件的部署机制允许指定这类不同的上下文。
二、类装载模式
当一个类被引用时,Java虚拟机(JVM)必须装入被引用的类。JVM利用一个标准的类装入机制把类装入内存,这个从源文件装入Java类的机制称为类装载器 。Java类可以从磁盘、网络或其他媒体装入,它们可以驻留在任何地方。多个类装载器可以按照父-子关系链接在一起,形成一种层次结构。由子类装载器装入的类能够看到(能 够使用)由任意父类装载器装入的类;由父类装载器装入的类不能看到由任意子类装载器装入的类。类装载器、EAR文件与应用部署有着重要关系,因为应用服务器可能采用专用的 类装载器部署应用模块。
如果在一个系统中,Web应用需要访问某个EJB,它就必须能够装入它所需要的那些类。由于这意味着不同模块之间的依赖关系,为了解决依赖问题,应用服务器必须 为EAR类装载器考虑不同的结构方案。
独立的应用程序部署在它自己的类装载器中。这意味着,如果分别地部署一个Web应用和一个EJB应用,每个应用的类将分别装入各自的、级别相同的类装入器,We b应用内的类不能看到另一个类装载器装入的类。如果Web应用想要使用那些分开部署的EJB,就会出现问题。
在EAR文件出现之前,许多开发者先部署EJB,然后以Web应用WEB-INF/lib目录一部分的形式,再次封装同一EJB JAR文件。这样,同一类文件必须放入两个不同的地方,才能让应用正常地运行。显然,这是一种应当避免的情形。EAR文件的引入就是为了解决这个问题。EAR文件不仅是 一种方便的封装格式,而且它还提供了一种特殊的类装载模式,允许EAR文件内的应用访问其他应用的类。
J2EE 1.3规范没有具体规定EAR类装载器应该如何运作。在决定类装入方式时,应用服务器供应商有着很大的自由。实现EAR类装载器之前,供应商必须决定:
EAR文件中所有应用的所有类由单一的类装载器装入,还是不同应用的文件由不同的类装载器装入?
在EAR文件中的不同应用之间,是否存在类装载器的父-子关系?例如,如果两个EJB应用依赖于log4j.jar,那么,是否应该由父类装载器装入log4j .jar,由子类装载器装入两个EJB应用,从而维持适当的可见性关系?
如果类装载器之间存在层次关系,那么这种层次关系允许扩展到什么程度?
多个EJB之间存在固有的关系,但Web应用没有。那么,EJB应用的装载方式是否应该和Web应用的不同,以便保持Web应用的完整性?
2.1 在EJB 2.0之前
在EJB 2.0 Public Final Draft 2之前,供应商在选择类装载模式方面有着很大的自由。如果JSP页面和Servlet要使用某个EJB,那么它们只需能够装入EJB的Home接口、远程接口、公共类和 Stub类。这里所谓的公共类包括异常类、参数类等,它们应该放入一个依赖JAR文件,作为一个有着依赖关系的包装入。在这种模式下,供应商必须为依赖于EJB的Web应 用选择一种装入Home接口、远程接口和Stub类的方式。
下面是这种类装载模式的一个简单实现(客户端应用在另一个虚拟机之内运行,与所有其他组件隔离,因此下面的模型不包含客户端应用的类装入过程。):
在这个模型中,每一个EAR应用将由一个定制的EAR类装载器实例装入,EJB应用和Web应用都由EAR类装载器的定制子类装载器装入。在EAR文件中,所有 准备给一个以上应用共享的类都由EAR类装载器装入,包括所有公用依赖库和资源适配器包。如果一个类由EAR类装载器装入,它将自动地可供所有由子类装载器装入的类使用。
所有EJB应用都由单一的EJB类装载器装入,这个EJB类装载器是EAR类装载器的子类装载器。即使存在多个不同的EJB JAR文件,它们也都由同一类装载器装入。这一机制有利于同一JVM之内不同应用之间进行的EJB到EJB的调用。
每一个Web应用都在不同的类装载器中装入,保持类之间的隔离。这是因为,如果每一个Web应用有一个名为index.jsp的文件,则从该JSP页面生成的S ervlet会有同样的类名字。由于每一个Web应用应该能够装入该Servlet的自己的版本,因此所有Web应用必须在各自的类装载器中隔离起来。
Web应用要使用在同一EAR文件内部署的EJB,必须能够看到这些EJB的外部接口和Stub实现类。由于EJB和Web应用的类装载器属于平等的关系(不是 父-子关系),Web应用不能直接看到必需的类文件。然而,Web应用类装载器和EJB应用类装载器有着相同的父类装载器。为了让Web应用能够使用EJB的类文件,EJ B类装载器获取各个EJB的公用接口和它们的Stub实现文件,然后把它们“导出”给EAR类装载器,在EAR类装载器中它们可以被EAR中的所有应用访问。公用接口和S tub实现文件就是客户程序调用EJB时要用到的类。这样,Web应用就能够装入使用所有EJB时需要用到的类。
依赖工具库可能在不同位置装入,具体由指定这些库的位置决定。如果一个Web应用在它的WEB-INF/lib目录下列出了一个依赖库,则该库只和这个Web应 用有关,其他应用无需访问该库的内容,因此该库不必由EAR类装载器装入。在这种情况下,Web应用类装载器将装入该库的JAR文件。其他Web应用如果也要使用该库,则 必须在它自己的WEB-INF/lib目录下提供。
如果依赖库由EJB和Web应用共享,则它必须由EAR类装载器装入。EAR类装载器将装入所有声明为EJB所依赖的库,使得依赖库中的类具有合适的可见性。这 就允许EJB开发者把所有公用的异常类、Web应用可见的定制输入参数类、EJB封装到一个依赖库里面。这个库常常称作common.jar,但并非一定得如此命名。
与EJB和Web应用一起在EAR文件内封装的资源适配器包将自动由EAR类装入器装入。
2.2 在EJB 2.0之后
EJB 2.0规范引入了本地引用这一概念,它允许通过“传递引用”(而不是“传递值”)的方式访问并存的客户程序和EJB组件。本地引用这一概念使EAR类装载问题发生了值得 注意的变化。
当EJB客户程序通过“传递引用”方式执行调用时,仅仅能够访问EJB的公用接口和Stub实现类是不够的。客户程序必须拥有一个EJB容器实现类的直接引用。 在本地引用方式下,EJB的客户程序需要比以前更多的信息,这意味着在EJB 2.0之前使用的类装载模式已不再有效。为解决这个问题,EJB客户程序的类装载器必须是EJB类装载器的子孙,如下图所示:
在这个模型中,Web应用类装载器是EJB类装载器的子孙。这使得所有Web应用能够访问它们作为EJB客户程序所需要的文件。不过,为实现隔离,每一个Web 应用仍在一个定制的类装载器中装入。从整体结构来看,新的模型更简洁、更容易理解,它不再要求EJB类装载器把任何文件导出给EAR类装载器。
J2EE规范没有明确规定Web应用的依赖库应该如何装载。如果一个工具类库通过WEB-INF/lib指定,很显然它应该保持隔离,只能由Web应用的类装载 器装入它;然而,如果通过其他方式指定了一个工具类是Web应用的依赖库,它应该由Web应用的类装载器装入,还是应该导出给EAR类装载器?J2EE没有对这一点作出具 体规定。
对于被指定为Web应用依赖库的工具类库,Silverstream应用服务器和J2EE参考实现在EAR类装载器级装入它们,WeLogic Server 6.0在Web应用类装载器中装入它们。但是,WebLogic Server 6.1改变了原来的办法,支持在EAR级别上装入Web应用依赖库。这种改变是有意义的,因为Web应用的隔离总是可以通过把工具类库放入WEB-INF/lib目录实 现。
(来源:j2ee14规范)
In addition to allowing access to referenced classes, as described above, any
resources contained in the referenced jar files must also be accessible using the
Class and ClassLoader getResource methods, as allowed by the security
permissions of the application. An application will typically have the security
permissions required to access resources in any of the jar files packaged with the
application.
 
谢谢xiangya。
我发两个相同的war包只是为了测试,呵呵,是复制一份再将其中一个改名字。
我已经单步跟踪到错误地点了,所以log已经不是很有用了。
再次谢谢xiangya
 
后退
顶部