作者:汤葱 (dev2dev id: peachpi)
在使用Weblogic的过程中,经常会碰到一些很“怪”的事情,说它怪,主要是因为这些事情表面上看去不可思议,不可能发生。比如,一个Jar包在别人的机器上能够部署,而在自己的机器上愣是部署不成功,而好像所有的设置都一样。抑或是某个应用刚刚还运行正常,怎么突然一下子又运行不了呢!但是,这些怪事情不可能凭空产生,肯定还是有其内在原因,只不过可能由于我们对其内部机理不是很了解,所以才会觉得怪。所以说,不弄清楚其内在根源,我们就永远不可能揭开事物的神秘面纱。在这里,我想就我日常碰到的一些怪问题做个总结,以给大家一个参考。
* 环境问题,Classpath在作怪
* 序列化问题
* java.rmi.UnmarshalException异常
* RequiredNew事务属性造成死锁现象
1、 环境问题
回到本文开头提到的Jar包部署不成功的问题,为什么同样的Jar包在不同的机器上部署会有不同的结果呢?而且,我们也确信两台机器上的weblogic配置完全一样,难道是weblogic本身出了什么问题,要不要重装weblogic甚至重装机器试试。记住,千万不要草率地做出这种决定。自己再仔细想一想,两个weblogic的配置真的完全一样吗?这个时候往往容易忽略一个最基本的问题:环境设置,也就是classpath设置。我们知道,在weblogic的启动脚本中一般是这样来设置classpath的:
set CLASSPATH=
%WEBLOGIC_CLASSPATH%;%POINTBASE_CLASSPATH%;%JAVA_HOME%jrelib t.jar;
%WL_HOME%serverlibwebservices.jar;%CLASSPATH%
所有的危机都隐藏在%CLASSPATH%中,当出现以上的问题后,先检查一下你本机的classpath设置,或者干脆将此项去掉,看看问题是否就解决了。
表象:同样的个体在不同的weblogic上有不同的表现。
根源:本机的classpath设置在作怪。
2、 序列化
有一次,在调试一个EJB程序的时候,发现客户端传给EJB的数据传输对象(DTO)的某些属性值神秘消失了,在客户端已经明确无误地将某个属性赋值传入,但是在EJB端就是获得不了该值,每次取到的都只是缺省值。起初怀疑是该DTO对象未实现序列化接口,但如果是这样程序应该会报错呀?而且该DTO类也已经实现了java.io.Serializable接口:
public class MyDTO extends DTOWrapImpl implements Serializable
在兜了一个圈子以后,还是将目光再次盯在了未序列化上。因为,我在实验的过程中发现并不是所有的属性的传入值都消失了,那为什么有些属性的传入值消失了呢?这个时候又看了一下代码,莫非是父类DTOWrapImpl没有实现java.io.Serializable接口?最终这个推测得到了证实,而那些传入值消失的属性恰恰都是在父类中定义的属性,同时由于DTO子类实现了java.io.Serializable接口,应用程序也没有提示错误。而这一切都是重构“惹的祸”,原来最初父类DTOWrapImpl是不存在的,后来由于要给这些DTO类增加一些共同的特性,所以增加了一个父类,但是却忘记了java.io.Serializable接口,咳!
表象:传入对象的某些属性值神秘消失了。
根源:检查一下该类的父类是否实现了java.io.Serializable接口。
3、 java.rmi.UnmarshalException异常
该异常一般发生在rmi操作中,Java API文档对于出现该异常的情况进行了总结,但是在weblogic上调用ejb时,该异常的产生可能会有些怪。记得有一次,在调试自己的程序时,发现Session Bean的方法调用抛出该异常,而这个程序昨天还是正常的,这中间也没有进行修改。开始还以为是weblogic出了什么问题,后来重新部署一下,一切OK。据我的总结,在排除其它原因的情况下,weblogic如果非正常停止,启动,甚至部署都可能会使你接下来的程序调用抛出该异常,而这个时候你只需要重新部署一遍即可。如果这还不行的话,可以重新编译打包(一定记得调用weblogic.appc),然后再部署,力求先排除这种很怪的可能。
表象: 在没有改变远程接口的情况下,抛出java.rmi.UnmarshalException异常。
根源:可能是由于对weblogic进行了一些非常规不正常操作,包括启动异常,异常停止以及部署异常。
4、 RequiredNew事务属性造成死锁现象
如果实体bean的某个方法的事务属性设置为RequiredNew,那么调用该方法就应该特别小心,否则很容易产生死锁现象。记得有一次,我在Command的exec方法中来调用一个事务属性为RequiredNew的setStatus方法,来改变帐户的状态,但是在此方法调用之前,帐户状态已经被改变,于是就产生了死锁现象。因为,setStatus方法相关的事务开始前,需要将对帐户状态的未决改变提交,但是对setStatus方法的调用本身又是exec方法的一部分。为了避免这种现象的发生,最好将对那些事务属性为RequiredNew的方法调用放在最前面执行。
表象:Command的某个方法执行产生死锁。
根源:该方法中有对事务属性为RequiredNew的实体bean方法的调用,并且在该方法调用之前改变了该方法关心的一些状态。
以上提到的这几点对于某些人来说可能不是什么问题,但是我想它可能曾经困扰过我们,而且将来也一定会困扰其它一些人,我希望通过这种总结的方式使更多的人少走弯路,但最重要的还是希望能够教会大家如何去分析一个怪问题。
我想,只有大家对怪问题背后的本质有了一个清醒的认识,才可能见怪不怪,很好地去解决它们。最好,我也希望大家能够和我一起,将这个“见怪不怪”系列进行下去,让更多的人能够从中受益。
关于作者:
汤葱,主要在J2EE平台上从事广电行业运营系统的开发工作,擅长组件技术,多层架构下的编程。