Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 438|回复: 0

Weblogic环境下hibernate、antlr类加载冲突问题分析及解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-9-3 15:27:04 | 显示全部楼层 |阅读模式

    公司应用项目在客户部署时经常遇到此类问题,为避免实施部署时增加配置量,花了点时间找到了此问题的终极解决办法(方案二、修改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类路径下已经存在antlrjar包了,系统会优先使用weblogic下的antlr包,而weblogic类路径下并没有hibnatejar包,所以在加载org.hibernate.hql.ast.HqlToken类是会抛出ClassNotFoundException: org.hibernate.hql.ast.HqlToken异常。

     

    三、解决方案

        方案一、修改weblogic类加载器中antlr加载的优先级

    1. 拷贝应用中的包antlr-2.7.6.jar%WL_HOME%\server\lib 
    2. 修改% mydomain%\startWebLogic.cmd(.sh)  
      set CLASSPATH之前加上下面一句: 
      set PRE_CLASSPATH=%WL_HOME%\server\lib\antlr-2.7.6.jar; 
      set CLASSPATH之后加上下面一句: 
      set CLASSPATH=%PRE_CLASSPATH%;%CLASSPATH% 

    此方案并不总是有效(尤其是在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...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-3 07:32 , Processed in 0.068827 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表