hibernate使用的文法分析器是antlr,weblogic同样也是。
不少用户碰到classnotfoundexception: org.hibernate.hql.ast.hqltoken的典型问题,这个典型问题已经通过
配置weblogic.xml,要求web应用优先加载web-inf的jar(即应用classloader)而非weblogic的system classloader得以勉强解决:
hibernate 3.0的用户发现上述的方法依然不能解决问题,因为hibernate使用了class.forname去load一个类,而jvm加载类的方式是先system classloader(weblogic),后application classloader(web应用),于是,应用即使采用prefer-web-inf-classes策略,但class.forname还是load了weblogic的antlr!!
hibernate 3.1迅速解决了这个问题,hibernate会使用context classloader,class.forname这种罪恶的代码已经被消除掉。
无独有偶,2005年,澳大利亚的suncorp-metway公司使用hibernate3.0.3 weblogic8.1sp4开发他们的应用 , 当时的weblogic 8.1sp4内置了antlr 2.7.1,跟hibernate 3.0.3捆绑的antlr-2.7.5h3.jar冲突,suncorp-metway公司希望改变weblogic的systemclasspath(加入antlr-2.7.5h3.jar),效果等于替换了weblogic的antlr,这当然能够解决hibernate的问题,但天知道会带来什么问题,因为weblogic自身会使用antlr去分析ejbql(如果不适用cmp,用户完全可以不管3721,置换weblogic的antlr版本了之),suncorp-metway公司担心这种替换对系统带来其他影响,希望bea仍然能够提供凯发k8网页登录的技术支持。
当时,作为bea在澳大利亚昆士兰州最大的bea客户,他们的建议当然受到足够的尊重。
为此,bea 8.1 sp4/sp5都提供了一个补丁,等同于升级了weblogic 8.1自带的antlr的版本,weblogic 8.1sp6以及weblogic 9.1开始都沿用这个变更。
很明显,这种办法不可能再次沿用到以后的sp,因为antlr以及hibernate的版本的更新速度远远高于weblogic service pack的更新速度,bea不可能不断地重构antlr来适应开源日新月异的api变化。
weblogic 8.1 sp6之后,当使用hibernate 3(策略是true)的antlr 2.7.6时候,轮到weblogic自身的servlet容器出问题(hibernate好了,weblogic出事了)抛出如下的antlr异常:
java.lang.classcastexception: antlr.commontoken
at antlr.charscanner.maketoken(charscanner.java:175)
at weblogic.servlet.jsp.jsplexer.mword(jsplexer.java:4723)
at weblogic.servlet.jsp.jsplexer.mxml_attributes(jsplexer.java:4309)
at weblogic.servlet.jsp.jsplexer.mtaglib_directive_body(jsplexer.java:5034)
at weblogic.servlet.jsp.jsplexer.mtaglib_directive(jsplexer.java:4905)
at weblogic.servlet.jsp.jsplexer.mdirective(jsplexer.java:4751)
at weblogic.servlet.jsp.jsplexer.mstandard_thing(jsplexer.java:2161)
at weblogic.servlet.jsp.jsplexer.mtoken(jsplexer.java:1947)
at weblogic.servlet.jsp.jsplexer.nexttoken(jsplexer.java:1820)
at weblogic.servlet.jsp.jsplexer.nexttoken(jsplexer.java:1820)
at weblogic.servlet.jsp.jsplexer.parse(jsplexer.java:963)
at weblogic.servlet.jsp.jspparser.doit(jspparser.java:106)
at weblogic.servlet.jsp.jspparser.parse(jspparser.java:234)
at weblogic.servlet.jsp.jsp2java.outputs(jsp2java.java:125)
这个问题是weblogic servlet容器没有意识到hibernate用户对antlr的版本需求:
1) 在老的antlr 2.7.1中,weblogic的servlet容器使用antlr.charscanner通过下面的方法
class.forname(string classname)
加载token,因为jsp编译的classes本身是基于weblogic系统classloader,于是,classloader当然使用weblogic的antlr版本(2.7.1),weblogic没有被hibernate的antlr(2.7.6)所影响,class.forname转型成system cl所规约的 antlr.commontoken不会有问题。
2)
而当weblogic antlr 2.7.1 hibernate antlr2.7.6一起使用的时候,servlet容器在charscanner使用 class.forname(string, boolean, classloader)去加载token,而第三个参数是注入了当前的应用的classloader,即weblogic被迫使用了hibernate的antlr 2.7.6,而最终会导致容器在将antlr 2.7.6的 commontoken转型成antlr 2.7.1的commontoken出现java.lang.classcastexception。
这种情况,只能做两件事情:
1)向bea索取此case的补丁
2)前置system classpath,让新版本的antlr永远放在前面。
讲述了这么多东西,其实,最终想揭示的问题是,无论是hibernate和weblogic,在一开始的时候都没有意识到开源代码重构的重要性。早期的weblogic确实已经xml parser付出版本冲突的代价,所以后期,很多xml包都被weblogic重新rename package(重构代码的一种方式)。
如果一开始,weblogic就使用com.bea.opensource.antlr来让自己的容器使用antlr,antlr冲突的这些问题肯定不会出现。
weblogic 10确实开始大规模重构jar包,不幸的是,这个世界上有一种潜规则叫做向后兼容,所以,true是我们j2ee初级阶段仍然需要接受的现实,当然
,你可以期待另外一种技术解决此问题——osgi,事实上,这个版本可能比我们想象的要快,或者就在weblogic 12g。