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加载的优先级

  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;

}

时间: 2024-12-15 10:06:18

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

osgi 环境下 hibernate 4 配置

准备将公司的老应用迁移到OSGI karaf平台上.很吐血的一点就是hibernate. 这玩意,真是超级麻烦的一个工程. classload是最头痛的一个问题.在Hibernate4上利用注册服务的方式 实现了 classloader的代理. 顺便提一句想用Hibernate3做reloadclass的同学们别妄想了. 除非是改源码. 标签: Hibernate Karaf [1].[代码] 核心代码创建 SessionFactory 跳至 [1] ? 1 2 3 4 5 6 7 8 9 10

PHP没有数据库连接池怎么破?PHP环境下使用Nginx ngx_http_limit_req_module模块的高负载解决方案

线上运行了一套辅助系统是利用了开源的PHP改的,之前也没怎么玩过PHP,没想到这玩意儿还是有不少坑的.突然某一天一个用户做线上活动推广,然后短时间内涌进来了上万的请求,然后数据库连接耗尽,短时间内几乎拖垮了整个系统.导致系统奔溃的有多方面原因,今天主要针对PHP没有数据库连接池的原因来分析. 在PHP里,数据库连接在请求到达时建立,请求结束时释放.如果同时几千个请求到达,那就同时会建立几千个数据库连接,非常恐怖.而且PHP木有比较好的数据库连接池驱动方案,所以我们得另想办法. 解决这种问题有三种

Linux环境下,traceroute返回一系列*原因分析

Traceroute transmits packets with small TTL (Time To Live) values. The TTL is an IP header field that is used to prevent packets from running into endless loops. When a router that handles the packet subtracts one from the packet's TTL. The packet ex

weblogic新建域-linux环境下

[[email protected] bin]#/oracle/middleware/wlserver_12.1/common/bin [[email protected] bin]# ./config.sh -mode=console <---------------------------------------------------------------------------------- Fusion Middleware 配置向导 ------------------------

多jdk环境下安装多个tomcat冲突解决配置方法

                                                 文章转载自:[169IT-最新最全的IT资讯] 参考方案一: 一个服务器两个jdk,一个是jdk1.4,一个是jdk1.6. 同样tomcat版本是,tomcat5.0和tomcat6.0.都安装在一个服务器上. tomcat5.0匹配jdk1.4, tomcat6.0匹配jdk1.6, 1.首先指定tomcat匹配的jdk tomcat/bin目录下 catalina.bat setclasspa

weblogic 12c下jxls导出excel报错Could not initialize class org.apache.poi.xssf.usermodel.XSSFVMLDrawing

周一,开发反馈weblogic 12c下jxls导出excel报错,公司环境和UAT环境均报错,看日志如下: 2016-06-08 09:16:55,825 ERROR org.jxls.util.TransformerFactory.createTransformer(TransformerFactory.java:40)[org.jxls.util.TransformerFactory] - Method createTransformer of org.jxls.transform.poi

Tomcat集群环境下session共享方案梳理(1)-通过memcached(MSM)方法实现

对于web应用集群的技术实现而言,最大的难点就是:如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块.要实现这一点, 大体上有两种方式: 一种是把所有Session数据放到一台服务器上或者数据库中,集群中的所有节点通过访问这台Session服务器来获取数据: 另一种就是在集群中的所有节点间进行Session数据的同步拷贝,任何一个节点均保存了所有的Session数据. Tomcat集群session同步方案有以下几种方式: 1)使用tomcat自带的

eclipse下 hibernate逆向数据库操作示例!!

做项目必然要先进行数据库表设计,然后根据数据库设计建立实体类(VO),这是理所当然的,但是到公司里做项目后,让我认识到,没有说既进行完数据库设计后还要再“自己”建立一变VO.意思是,在项目设计时,要么根据需求分析建立实体类,由正向生成数据库表:要么就先进行数据库表设计,再逆向生成实体类.没有说进行完任意一方的设计后再去花时间去自己匹配建立另一方的设计. 原因是: 1. 1.5倍工作量,浪费时间.(时间对公司来说很重要) 2. 无法保证两边映射一致.因为两边都是自己设计的,那么就需要人为保证映射关

SQLite在多线程环境下的应用

这几天研究了一下SQLite这个嵌入式数据库在多线程环境下的应用,感觉里面的学问还挺多,于是就在此分享一下. AD: 2014WOT全球软件技术峰会北京站 课程视频发布 先说下初衷吧,实际上我经常看到有人抱怨SQLite不支持多线程.而在iOS开发时,为了不阻塞主线程,数据库访问必须移到子线程中.为了解决这个矛盾,很有必要对此一探究竟. 关于这个问题,最权威的解答当然是SQLite官网上的“Is SQLite threadsafe?”这个问答. 简单来说,从3.3.1版本开始,它就是线程安全的了