程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA綜合教程 >> Weblogic環境下hibernate、antlr類加載沖突問題分析及解決方案,weblogicantlr

Weblogic環境下hibernate、antlr類加載沖突問題分析及解決方案,weblogicantlr

編輯:JAVA綜合教程

Weblogic環境下hibernate、antlr類加載沖突問題分析及解決方案,weblogicantlr


公司應用項目在客戶部署時經常遇到此類問題,為避免實施部署時增加配置量,花了點時間找到了此問題的終極解決辦法(方案二、修改org.hibernate.hql.ast.HqlLexer的源代碼)。在此進行記錄本問題的分析解決方案。

一、問題現象描述:

1、異常信息:

'weblogic.kernel.Default (self-tuning)']…

org.hibernate.QueryException: ClassNotFoundException: org.hibernate.hql.ast.HqlToken [

 

    at org.hibernate.hql.ast.HqlLexer.panic(HqlLexer.java:57)

    at antlr.CharScanner.setTokenObjectClass(CharScanner.java:340)

    at org.hibernate.hql.ast.HqlLexer.setTokenObjectClass(HqlLexer.java:31)

    at antlr.CharScanner.<init>(CharScanner.java:51)

    at antlr.CharScanner.<init>(CharScanner.java:60)

    at org.hibernate.hql.antlr.HqlBaseLexer.<init>(HqlBaseLexer.java:56)

    at org.hibernate.hql.antlr.HqlBaseLexer.<init>(HqlBaseLexer.java:53)

    at org.hibernate.hql.antlr.HqlBaseLexer.<init>(HqlBaseLexer.java:50)

    at org.hibernate.hql.ast.HqlLexer.<init>(HqlLexer.java:26)

    at org.hibernate.hql.ast.HqlParser.getInstance(HqlParser.java:44)

    at org.hibernate.hql.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:242)

    atorg.hibernate.hql.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:157)

    at org.hibernate.hql.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:111)

    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:77)

    at org.hibernate.engine.query.HQLQueryPlan.<init>(HQLQueryPlan.java:56)

    at org.hibernate.engine.query.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:72)

    at org.hibernate.impl.SessionFactoryImpl.checkNamedQueries(SessionFactoryImpl.java:402)

    at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:352)

    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294)

2、查詢weblogic安裝目錄下的antlr包:

3、應用中引用的是hibernate3和antlr_2.7.6的jar

 

二、原因分析

根據以上異常信息查看hibernate及antlr的源代碼:

org.hibernate.hql.ast.HqlLexer的部分代碼:

public void setTokenObjectClass(String cl) {        

super.setTokenObjectClass( HqlToken.class.getName() );

        }

以上super.setTokenObjectClass 方法就是antlr.CharScanner類中定義的方法:

public void setTokenObjectClass(String paramString) {

    try {

      this.tokenObjectClass = Utils.loadClass(paramString);

    } catch (ClassNotFoundException localClassNotFoundException) {

      panic("ClassNotFoundException: " + paramString);

    }

}

此方法的關鍵部分:Utils.loadClass(paramString);即在hibernate在解析hql是會采用此工具加載org.hibernate.hql.ast.HqlToken類(即HqlLexer類中的setTokenObjectClass方法)。此處會發生什麼情況呢,請看Utils.loadClass的源代碼:

  static {

          if ("true".equalsIgnoreCase(System.getProperty("ANTLR_DO_NOT_EXIT", "false")))

              useSystemExit = false;

          if ("true".equalsIgnoreCase(System.getProperty("ANTLR_USE_DIRECT_CLASS_LOADING", "false")))

              useDirectClassLoading = true;

  }

 

    /** Thanks to Max Andersen at JBOSS and Scott Stanchfield */

    public static Class loadClass(String name) throws ClassNotFoundException {

        try {

            ClassLoader contextClassLoader =Thread.currentThread(). getContextClassLoader();

            if (!useDirectClassLoading && contextClassLoader!=null ) {

                return contextClassLoader.loadClass(name);

            }

            return Class.forName(name);

        }

        catch (Exception e) {

            return Class.forName(name);

        }

    }

 

從以上的代碼可看處,加載org.hibernate.hql.ast.HqlToken類的類加載器是weblogic啟動類加載器(不管是Thread.currentThread().getContextClassLoader()還是Class.forName,其中Class.forName采用的是Reflection.getCallerClass()的類加載器,即antlr的類加載器),並非應用類加載器。Weblogic類路徑下已經存在antlr的jar包了,系統會優先使用weblogic下的antlr包,而weblogic類路徑下並沒有hibnate的jar包,所以在加載org.hibernate.hql.ast.HqlToken類是會拋出ClassNotFoundException: org.hibernate.hql.ast.HqlToken異常。

 

三、解決方案

    方案一、修改weblogic類加載器中antlr加載的優先級

此方案並不總是有效(尤其是在osgi類型項目或者同一個weblogic域下部署多個項目的情況),當然根據筆者遇到的情況成功率也在95%以上。當此方案無效時可以采用方案二。

    方案二、修改org.hibernate.hql.ast.HqlLexer的源代碼:

        加載org.hibernate.hql.ast.HqlToken類是,直接用hibernate所在類classload加載即可:

    將原來的代碼:

  public void setTokenObjectClass(String cl) {        

super.setTokenObjectClass( HqlToken.class.getName() );

        }

 

    修改為:直接將hqltoken類賦值給this.tokenObjectClass

public void setTokenObjectClass(String cl) {

    this.tokenObjectClass = HqlToken.class;

}

    

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved