Weblogic环境下hibernate、antlr类加载冲突问题分析及解决方案
公司应用项目在客户部署时经常遇到此类问题,为避免实施部署时增加配置量,花了点时间找到了此问题的终极解决办法(方案二、修改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加载的优先级
- 拷贝应用中的包antlr-2.7.6.jar到%WL_HOME%\server\lib下
 - 修改% 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;
}
Weblogic环境下hibernate、antlr类加载冲突问题分析及解决方案的更多相关文章
- 在windows环境下运行compass文件出现的错误提示解决方案
		
在windows环境下运行compass文件出现的错误提示解决方案 例如:经常在项目中运行grunt命令编译scss文件的时候,会出现下面的错误提示 (Encoding::CompatibilityE ...
 - 痞子衡嵌入式:在IAR开发环境下RT-Thread工程函数重定向失效分析
		
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在IAR开发环境下RT-Thread工程函数重定向失效分析. 痞子衡旧文 <在IAR下将关键函数重定向到RAM中执行的方法> ...
 - JNI各种环境下编译方法及初期出错分析
		
转自 https://www.cnblogs.com/xyang0917/p/4172490.html 第五步.将C/C++代码编译成本地动态库文件 动态库文件名命名规则:lib+动态库文件名+后缀( ...
 - BAE 环境下 hibernate annotations 配置
		
annotations 配置 首先需要加入 hibernate-jpa-2.0-api-1.0.1.Final.jar 和 ejb3-persistence.jar 这两个包 ejb3-persis ...
 - 在eclipse环境下使用maven install 命令碰到native2ascii-utf8问题解决方案
		
报错语句:Failed to execute goal org.codehaus.mojo:native2ascii-maven-plugin:1.0-beta-1:native2ascii (nat ...
 - win10环境下pyinstaller打包pytorch遇到的问题及解决方案
		
pytorch-python源码生成windows的应用程序(.exe),报错OSError: could not get source code Failed to execute script h ...
 - Git 常见问题 冲突原因分析及解决方案
		
仅结合本人使用场景,方法可能不是最优的 1. 忽略本地修改,强制拉取远程到本地 主要是项目中的文档目录,看的时候可能多了些标注,现在远程文档更新,本地的版本已无用,可以强拉 git fetch --a ...
 - 【Tesseract-OCR】在VS2012环境下调用API方法---注意避免名字冲突
		
由于在VS2012中使用OpenCV可以得到插件ImageWatch.vsix的支持,查看图像非常方便,所以一直想在VS2012环境下把Tesseract-OCR融合进来,但是这一错误折腾了我好久: ...
 - eclipse环境下基于已构建struts2项目整合spring+hibernate
		
本文是基于已构建的struts2项目基础上整合 spring+hibernate,若读者还不熟悉struts2项目,请先阅读 eclipse环境下基于tomcat-7.0.82构建struts2项目 ...
 
随机推荐
- 安装minicom串口访问开发板
			
1. 安装minicom yum install minicom 2. 设置minicom minicom -s 选择“Serial port setup”,将“Serial Device”修改成 ...
 - rpm软件包
			
安装软件:rpm -i software.rpm卸载软件:rpm -e software升级形式安装:rpm -U software-new.rpmrpm支持通过http.ftp协议安装软件:rpm ...
 - js实现文字截断
			
先前用jq做了一个文字截断功能,但是不用jq的项目要实现此功能还要引如jq显得过于麻烦.这里写了一个js的文字截断功能.直接上代码. HTML(测试用的): <div>我是pox我是pox ...
 - GoldenGate中使用FILTER,COMPUTE 和SQLEXEC命令
			
本文主要介绍OGG中一些过滤或计算函数的用法,以及sqlexec的基本用法 SQLPREDICATE 在使用OGG初始化时,可以添加此参数到extract中,用于选择符合条件的记录,下面是OGG官方文 ...
 - 关于MongoDb Replica Set的故障转移集群——理论篇
			
自从10 gen用Replica Set取代Master/Slave方案后生活其实已经容易多了,但是真正实施起来还是会发现各种各样的小问题,如果不小心一样会栽跟头. 在跟Replica Set血拼几天 ...
 - Mysql查询(笔记二)
			
1.两结构相同的表数据间移植 Inset into 表一 Select 字段1,字段2,....字段n from表二 建立数据库时设置数据库编码 create database 数据库名 charse ...
 - Linux安全运维日志排查几个 tips
			
运维日志排查记录 前言 记录一些排查常见日志的命令,方法wiki,欢迎补充(Markdown 语法). 常用命令 查找关键词并统计行数 cat 2015_7_25_test_access.log | ...
 - 通过Sql语句控制SQLite数据库增删改查
			
person类属性有Intenger id,String name,Intenger age,相应的构造方法和set get方法. package com.xh.tx.dao; import jav ...
 - 4)Java容器类相关知识
			
1>Array 和 Arrays: Arrays:用来操作array的工具类,其中包含一组static函数: equals():比较两个array 是否相等. array拥有相同元 ...
 - js控制文本框只能输入数字 及 常用字符对应ASCII码值
			
方法一: <INPUT TYPE='text' NAME=text onkeypress="a()"><script language=javascript> ...