David.Turing's blog

           

          [原創(chuàng)]Hibernate的Antlr在Weblogic中產(chǎn)生Jar沖突的歷史緣故以及解決辦法

          Hibernate使用的文法分析器是antlr,WebLogic同樣也是。
          不少用戶碰到ClassNotFoundException: org.hibernate.hql.ast.HqlToken的典型問題,這個(gè)典型問題已經(jīng)通過
          配置weblogic.xml,要求Web應(yīng)用優(yōu)先加載WEB-INF的Jar(即應(yīng)用Classloader)而非WebLogic的System Classloader得以勉強(qiáng)解決:
          <weblogic-web-app>
          ? <container-descriptor>
          ? ? <prefer-web-inf-classes>true</prefer-web-inf-classes>
          ? </container-descriptor>
          </weblogic-web-app>
          ?
          ?
          Hibernate 3.0的用戶發(fā)現(xiàn)上述的方法依然不能解決問題,因?yàn)镠ibernate使用了Class.forName去Load一個(gè)類,而JVM加載類的方式是先System Classloader(WebLogic),后Application Classloader(Web應(yīng)用),于是,應(yīng)用即使采用prefer-web-inf-classes策略,但Class.forName還是Load了WebLogic的Antlr!!
          ?
          Hibernate 3.1迅速解決了這個(gè)問題,Hibernate會(huì)使用context classloader,Class.forName這種罪惡的代碼已經(jīng)被消除掉。
          ?
          無獨(dú)有偶,2005年,澳大利亞的Suncorp-Metway公司使用Hibernate3.0.3 + WebLogic8.1SP4開發(fā)他們的應(yīng)用 , 當(dāng)時(shí)的WebLogic 8.1SP4內(nèi)置了antlr 2.7.1,跟Hibernate? 3.0.3捆綁的antlr-2.7.5H3.jar沖突,Suncorp-Metway公司希望改變WebLogic的SystemClassPath(加入antlr-2.7.5H3.jar),效果等于替換了WebLogic的Antlr,這當(dāng)然能夠解決Hibernate的問題,但天知道會(huì)帶來什么問題,因?yàn)閃ebLogic自身會(huì)使用Antlr去分析EJBQL(如果不適用CMP,用戶完全可以不管3721,置換WebLogic的Antlr版本了之),Suncorp-Metway公司擔(dān)心這種替換對(duì)系統(tǒng)帶來其他影響,希望BEA仍然能夠提供技術(shù)支持。
          當(dāng)時(shí),作為BEA在澳大利亞昆士蘭州最大的BEA客戶,他們的建議當(dāng)然受到足夠的尊重。 為此,BEA 8.1 SP4/SP5都提供了一個(gè)補(bǔ)丁,等同于升級(jí)了WebLogic 8.1自帶的Antlr的版本,WebLogic 8.1SP6以及WebLogic 9.1開始都沿用這個(gè)變更。
          ?
          很明顯,這種辦法不可能再次沿用到以后的SP,因?yàn)锳ntlr以及Hibernate的版本的更新速度遠(yuǎn)遠(yuǎn)高于WebLogic Service pack的更新速度,BEA不可能不斷地重構(gòu)Antlr來適應(yīng)開源日新月異的API變化。
          ?
          WebLogic 8.1 SP6之后,當(dāng)使用Hibernate 3(策略是<prefer-web-inf-classes>true</prefer-web-inf-classes>)的Antlr 2.7.6時(shí)候,輪到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)

          這個(gè)問題是WebLogic Servlet容器沒有意識(shí)到Hibernate用戶對(duì)ANTLR的版本需求:
          1) 在老的Antlr 2.7.1中,WebLogic的Servlet容器使用antlr.CharScanner通過下面的方法 ?Class.forName(String className) 加載token,因?yàn)閖sp編譯的classes本身是基于WebLogic系統(tǒng)Classloader,于是,Classloader當(dāng)然使用WebLogic的Antlr版本(2.7.1),WebLogic沒有被Hibernate的Antlr(2.7.6)所影響,Class.forName轉(zhuǎn)型成System CL所規(guī)約的 antlr.CommonToken不會(huì)有問題。
          2) 而當(dāng)WebLogic Antlr 2.7.1+Hibernate Antlr2.7.6一起使用的時(shí)候,Servlet容器在CharScanner使用 Class.forName(String, boolean, ClassLoader)去加載token,而第三個(gè)參數(shù)是注入了當(dāng)前的應(yīng)用的Classloader,即WebLogic被迫使用了Hibernate的Antlr 2.7.6,而最終會(huì)導(dǎo)致容器在將Antlr 2.7.6的 CommonToken轉(zhuǎn)型成Antlr 2.7.1的CommonToken出現(xiàn)java.lang.ClassCastException。
          ?
          這種情況,只能做兩件事情:
          1)向BEA索取此Case的補(bǔ)丁
          2)前置System ClassPath,讓新版本的Antlr永遠(yuǎn)放在前面。
          ?
          ?
          講述了這么多東西,其實(shí),最終想揭示的問題是,無論是Hibernate和WebLogic,在一開始的時(shí)候都沒有意識(shí)到開源代碼重構(gòu)的重要性。早期的WebLogic確實(shí)已經(jīng)XML Parser付出版本沖突的代價(jià),所以后期,很多XML包都被WebLogic重新Rename Package(重構(gòu)代碼的一種方式)。 如果一開始,WebLogic就使用com.bea.opensource.antlr來讓自己的容器使用Antlr,ANTLR沖突的這些問題肯定不會(huì)出現(xiàn)。
          ?
          WebLogic 10確實(shí)開始大規(guī)模重構(gòu)Jar包,不幸的是,這個(gè)世界上有一種潛規(guī)則叫做向后兼容,所以,<prefer-web-inf-classes>true</prefer-web-inf-classes>是我們J2EE初級(jí)階段仍然需要接受的現(xiàn)實(shí),當(dāng)然
          ,你可以期待另外一種技術(shù)解決此問題——OSGI,事實(shí)上,這個(gè)版本可能比我們想象的要快,或者就在WebLogic 12g。

          posted on 2008-07-04 23:24 david.turing 閱讀(7884) 評(píng)論(1)  編輯  收藏

          評(píng)論

          # re: [原創(chuàng)]Hibernate的Antlr在Weblogic中產(chǎn)生Jar沖突的歷史緣故以及解決辦法 2009-07-30 16:07 小池

          很到位,thanks  回復(fù)  更多評(píng)論   


          只有注冊用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(110)

          我參與的團(tuán)隊(duì)

          隨筆分類(126)

          隨筆檔案(155)

          文章分類(9)

          文章檔案(19)

          相冊

          搜索

          積分與排名

          最新隨筆

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 宁都县| 开封县| 隆林| 淮安市| 厦门市| 柞水县| 绥江县| 朝阳市| 当阳市| 祥云县| 伊春市| 襄汾县| 苏尼特右旗| 茌平县| 定边县| 崇左市| 上林县| 应城市| 信丰县| 体育| 安平县| 文昌市| 扎兰屯市| 张家川| 剑川县| 长葛市| 永清县| 祁东县| 沙田区| 砀山县| 加查县| 长泰县| 彰武县| 上犹县| 麻栗坡县| 青浦区| 金门县| 胶南市| 长武县| 阿鲁科尔沁旗| 大竹县|