- 浏览: 1526156 次
- 性别:
- 来自: 厦门
博客专栏
-
Spring 3.x企业实...
浏览量:463899
文章分类
最新评论
-
JyeChou:
学习Spring必学的Java基础知识(1)----反射 -
hhzhaoheng:
...
《Spring4.x企业应用开发实战》光盘资料下载 -
renlongnian:
//assertReflectionEquals(user1, ...
单元测试系列之3:测试整合之王Unitils -
骑着蜗牛超F1:
huang_yong 写道我的经验是,只需定义三层:1.ent ...
Spring的事务管理难点剖析(2):应用分层的迷惑 -
wangyudong:
工具地址貌似更新了哦https://github.com/Wi ...
几种常用的REST webservice客户端测试工具
概述
Javeer们一定遇到过NoSuchMethodError的错误,一旦碰到这种错误,必是JAR包版本冲突的问题无疑,版本冲突分开为以下两种情况:
构件版本冲突既可以在开发环境时发生,也有可能在开发环境下没有问题,部署到生产环境下才发生。这是因为JVM的类加载机制决定的,当JVM需要某个Class时,它先看JVM内部有没有这个Class,如果有就直接使用,如果没有才在类路径下加载新的JAR。如果JVM加载到A-x.jar,但实现上我们却需要A-y.jar,则恶魔就从瓶子里出来了。
解决招数
同构件多版本冲突
对于我们需要A-x.jar,JVM却加载到A-y.jar的情况,我们只要将类路径下那个A-y.jar移除,或者通过应用服务器的JAR优先加载顺序机制让A-x.jar优先于A-y.jar就OK了。对于TOMCAT,WAS等应用服务器,都有设置JAR的优先加载策略,如是以项目的类路径优先,还是应用服务器的共享类路径优先。如果是以共享类路径优先,假设共享类路径下有一个A-y.jar,则你项目WEB-INF/lib下的A-x.jar就加载不到。
所以解决这个问题的核心在于:找到运行期Class类到底是从哪个JAR包加载的。在开发环境下,可以使用断点查看类实例源自的JAR,下面提供了一个获取实例类所在位置的工具类:
在任何断点处动态执行该类就可看到类源自的JAR包了,找到JAR包你就可以分析到底是不是你想要的那个版本(下图是演示在IDE下通过ALT+F8打开Evaluate Expression对话框动态查看Class所在JAR包):
在生产环境下,你可以通过写LOG日志输出来查看,但这种方式需要你代码中有写日志的代码,可能涉及到重新编译和部署,肯定不是最好的方式。最好的是打开一个页面,通过输入类名获取类所在的路径信息,下面是一个完成此功能的JSP:
打开页面,通过URL参数指定类名,页面即可显示类加载自哪个JAR了,非常方便!
协作构件版本冲突
针对协作构件之间的版本冲突,其实就是要找到协作构件之间的匹配版本了,一般情况下,主构件的发布网站都会有相关帮助文档给出明确的说明,如Apache POI,其poi-ooxml构件需要依赖于poi-ooxml-schemas构件,版本的匹配关系说明如下:
poi-ooxml requires poi-ooxml-schemas. This is a substantially smaller version of the ooxml-schemas jar (ooxml-schemas-1.3.jar for POI 3.14 or later, ooxml-schemas-1.1.jar for POI 3.7 up to POI 3.13, ooxml-schemas-1.0.jar for POI 3.5 and 3.6). The larger ooxml-schemas jar is normally only required for development. Similarly, the ooxml-security jar, which contains all of the classes relating to encryption and signing, is normally only required for development. A subset of its contents are in poi-ooxml-schemas. This JAR is ooxml-security-1.1.jar for POI 3.14 onwards and ooxml-security-1.0.jar prior to that.
以上说明引用自apache的网站:http://poi.apache.org/overview.html
再如Mockito和PowerMock版本匹配也可以从powermock的网站中找到:
https://github.com/jayway/powermock/wiki/MockitoUsage
简单的方法当然是找搜索引擎了,度娘找这种不够了,谷哥不在,用bing吧,关键词把两个构件名写入搜索,如在bing中搜索:
小结
相对来说,同构件多版本冲突好解决些,找到源JAR看一眼不对换掉或更改应用服务器JVM 类加载顺序即可。但构件版本匹配冲突则不太好解决,一定要尽量上其官网查资料,不要做无谓的换包尝试哦。
以后在此维护新文章:
https://www.jianshu.com/u/d7f090245ddd
Javeer们一定遇到过NoSuchMethodError的错误,一旦碰到这种错误,必是JAR包版本冲突的问题无疑,版本冲突分开为以下两种情况:
- 同构件多版本冲突:类路径同时中存在多个相同构件的版本,如即存在poi-ooxml-3.11.jar,又存在poi-ooxml-3.9.jar,项目真正运行时需要的是3.11,而JVM加载到的是3.9,这种情况,我们称之为“同构多版本冲突”;
- 协作构件版本冲突:假设构件A依赖于构件B,A的x版本需要B的y版本,如果引入的是B的z版本,那么A和B就不能很好的搭档,冲突产生,此为“协作构件版本冲突”。
构件版本冲突既可以在开发环境时发生,也有可能在开发环境下没有问题,部署到生产环境下才发生。这是因为JVM的类加载机制决定的,当JVM需要某个Class时,它先看JVM内部有没有这个Class,如果有就直接使用,如果没有才在类路径下加载新的JAR。如果JVM加载到A-x.jar,但实现上我们却需要A-y.jar,则恶魔就从瓶子里出来了。
解决招数
同构件多版本冲突
对于我们需要A-x.jar,JVM却加载到A-y.jar的情况,我们只要将类路径下那个A-y.jar移除,或者通过应用服务器的JAR优先加载顺序机制让A-x.jar优先于A-y.jar就OK了。对于TOMCAT,WAS等应用服务器,都有设置JAR的优先加载策略,如是以项目的类路径优先,还是应用服务器的共享类路径优先。如果是以共享类路径优先,假设共享类路径下有一个A-y.jar,则你项目WEB-INF/lib下的A-x.jar就加载不到。
所以解决这个问题的核心在于:找到运行期Class类到底是从哪个JAR包加载的。在开发环境下,可以使用断点查看类实例源自的JAR,下面提供了一个获取实例类所在位置的工具类:
import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.security.CodeSource; import java.security.ProtectionDomain; public class ClassLocationUtils { public static String where(String className){ try { Class<?> theClazz = Class.forName(className); return where(theClazz); } catch (ClassNotFoundException e) { return "CLASS_NOT_FOUND:"+className; } } /** * 获取类所有的路径 * @param cls * @return */ public static String where(final Class cls) { if (cls == null)throw new IllegalArgumentException("null input: cls"); URL result = null; final String clsAsResource = cls.getName().replace('.', '/').concat(".class"); final ProtectionDomain pd = cls.getProtectionDomain(); if (pd != null) { final CodeSource cs = pd.getCodeSource(); if (cs != null) result = cs.getLocation(); if (result != null) { if ("file".equals(result.getProtocol())) { try { if (result.toExternalForm().endsWith(".jar") || result.toExternalForm().endsWith(".zip")) result = new URL("jar:".concat(result.toExternalForm()) .concat("!/").concat(clsAsResource)); else if (new File(result.getFile()).isDirectory()) result = new URL(result, clsAsResource); } catch (MalformedURLException ignore) {} } } } if (result == null) { final ClassLoader clsLoader = cls.getClassLoader(); result = clsLoader != null ? clsLoader.getResource(clsAsResource) : ClassLoader.getSystemResource(clsAsResource); } return result.toString(); } }
在任何断点处动态执行该类就可看到类源自的JAR包了,找到JAR包你就可以分析到底是不是你想要的那个版本(下图是演示在IDE下通过ALT+F8打开Evaluate Expression对话框动态查看Class所在JAR包):
在生产环境下,你可以通过写LOG日志输出来查看,但这种方式需要你代码中有写日志的代码,可能涉及到重新编译和部署,肯定不是最好的方式。最好的是打开一个页面,通过输入类名获取类所在的路径信息,下面是一个完成此功能的JSP:
<%@page contentType="text/html; charset=UTF-8"%> <%@page import="java.io.File,java.net.*,java.io.*"%> <%! public static URL getClassLocation(final Class cls) { if (cls == null)throw new IllegalArgumentException("null input: cls"); URL result = null; final String clsAsResource = cls.getName().replace('.', '/').concat(".class"); final ProtectionDomain pd = cls.getProtectionDomain(); // java.lang.Class contract does not specify if 'pd' can ever be null; // it is not the case for Sun's implementations, but guard against null // just in case: if (pd != null) { final CodeSource cs = pd.getCodeSource(); // 'cs' can be null depending on the classloader behavior: if (cs != null) result = cs.getLocation(); if (result != null) { // Convert a code source location into a full class file location // for some common cases: if ("file".equals(result.getProtocol())) { try { if (result.toExternalForm().endsWith(".jar") || result.toExternalForm().endsWith(".zip")) result = new URL("jar:".concat(result.toExternalForm()) .concat("!/").concat(clsAsResource)); else if (new File(result.getFile()).isDirectory()) result = new URL(result, clsAsResource); } catch (MalformedURLException ignore) {} } } } if (result == null) { // Try to find 'cls' definition as a resource; this is not // document.d to be legal, but Sun's implementations seem to //allow this: final ClassLoader clsLoader = cls.getClassLoader(); result = clsLoader != null ? clsLoader.getResource(clsAsResource) : ClassLoader.getSystemResource(clsAsResource); } return result; } %> <html> <head> <title>srcAdd.jar</title> </head> <body bgcolor="#ffffff"> 使用方法,className参数为类的全名,不需要.class后缀,如 srcAdd.jsp?className=java.net.URL <% try { String classLocation = null; String error = null; String className = request.getParameter("className"); classLocation = ""+getClassLocation(Class.forName(className)); if (error == null) { out.print("类" + className + "实例的物理文件位于:"); out.print("<hr>"); out.print(classLocation); } else { out.print("类" + className + "没有对应的物理文件。<br>"); out.print("错误:" + error); } }catch(Exception e) { out.print("异常。"+e.getMessage()); } %> </body> </html>
打开页面,通过URL参数指定类名,页面即可显示类加载自哪个JAR了,非常方便!
协作构件版本冲突
针对协作构件之间的版本冲突,其实就是要找到协作构件之间的匹配版本了,一般情况下,主构件的发布网站都会有相关帮助文档给出明确的说明,如Apache POI,其poi-ooxml构件需要依赖于poi-ooxml-schemas构件,版本的匹配关系说明如下:
引用
poi-ooxml requires poi-ooxml-schemas. This is a substantially smaller version of the ooxml-schemas jar (ooxml-schemas-1.3.jar for POI 3.14 or later, ooxml-schemas-1.1.jar for POI 3.7 up to POI 3.13, ooxml-schemas-1.0.jar for POI 3.5 and 3.6). The larger ooxml-schemas jar is normally only required for development. Similarly, the ooxml-security jar, which contains all of the classes relating to encryption and signing, is normally only required for development. A subset of its contents are in poi-ooxml-schemas. This JAR is ooxml-security-1.1.jar for POI 3.14 onwards and ooxml-security-1.0.jar prior to that.
以上说明引用自apache的网站:http://poi.apache.org/overview.html
再如Mockito和PowerMock版本匹配也可以从powermock的网站中找到:
https://github.com/jayway/powermock/wiki/MockitoUsage
简单的方法当然是找搜索引擎了,度娘找这种不够了,谷哥不在,用bing吧,关键词把两个构件名写入搜索,如在bing中搜索:
小结
相对来说,同构件多版本冲突好解决些,找到源JAR看一眼不对换掉或更改应用服务器JVM 类加载顺序即可。但构件版本匹配冲突则不太好解决,一定要尽量上其官网查资料,不要做无谓的换包尝试哦。
以后在此维护新文章:
https://www.jianshu.com/u/d7f090245ddd
发表评论
-
狂魔型代码改造记
2016-10-22 13:02 2168功能需求 统计员工指定月:在职员工数,入职员工数,离职员 ... -
关于Websphere 会话管理若干奇葩问题
2015-12-09 20:45 4474引言 由于最近 ... -
几种常用的REST webservice客户端测试工具
2015-07-30 16:11 9706引言 开发了Rest WebService服务后,如果方便快捷 ... -
如何通过项目配置文件指定Log4J的配置文件
2015-07-28 21:47 12812引言 在打造易于部署的WEB应用项目 一文中,我们介绍了如何对 ... -
打造易于部署的WEB应用项目
2015-07-27 16:46 3026概述 很多WEB应用的配置文件位于项目的类路径下(如WEB-I ... -
ROCA Resource-oriented Client Architecture
2014-03-21 18:16 1770ROCA Resource-oriented Client ... -
关于Idea testng单元测试乱码的解决
2013-07-02 10:50 14162问题 我是使用intel ... -
网络技术专业名词
2012-11-07 15:30 1529MRTG 求助编辑百科名片 Multi Router Tr ... -
ETL及BI开源工具
2012-08-01 16:17 56311. Kettle Kettle是一款 ... -
HMAC简介
2012-06-11 12:38 5654HMAC简介 HMAC的典型应用 ... -
关于权限管理的一点小思考
2012-05-26 15:32 2480做任何系统组织结构和权限管理是必不可少的,同时也是最重要的,实 ... -
看看人家写东西的速度
2012-05-14 16:08 2215以下是GIT的开发日志: 2005 年4月3日 开始开发GIT ... -
明明白白AOP(傻瓜也会心领神会!)
2012-05-05 11:04 10577引子: AOP(面向方面编 ... -
学习Spring必学的Java基础知识(2)----动态代理
2012-05-02 13:03 9689引述要学习Spring框架的 ... -
单元测试系列之5:使用unitils测试Service层
2012-04-14 10:48 18437引述:Spring 的测试框架为我们提供一个强大的测试环境,解 ... -
如何用Spring读取JAR中的文件
2012-04-13 17:22 18389使用如下方式读取JAR中的文件出错 类路径下 ... -
单元测试系列之4:使用Unitils测试DAO层
2012-04-12 16:32 19674Spring 的测试框架为我们提供一个强大的测试环境,解 ... -
单元测试系列之3:测试整合之王Unitils
2012-04-09 14:11 15636引述:程序测试对保障应用程序正确性而言,其重要性怎么样强调都不 ... -
犯下这种错误,羞愧难当!
2012-03-28 15:06 2284我很早就过了SJCP,可是在实际项目中居然还是犯下了一个 ... -
单元测试系列之1:开发测试的那些事儿
2012-03-28 12:52 10009引述:程序测试对保障应用程序正确性而言,其重要性怎 ...
相关推荐
不会与poi的版本产生冲突 4、加载至maven中 5、涉及到的jar冲突,取决于自己的项目 pom示例:项目中存在冲突再 exclusion 添加即可 <groupId>com.customize</groupId> <artifactId>easyexcel <version>2.2.6 ...
OSGi(Open Services Gateway Initiative)是一种模块化系统和Java服务框架,它允许在单个JVM上运行多个版本的相同库或服务,从而解决了不同版本jar包冲突的问题。本示例通过一个名为“myself”的工程,展示了如何...
jar包冲突通常发生在引入了多个依赖库,而这些库中有相同类的不同版本时。"jar包冲突检测工具"正是为了解决这个问题而设计的。 这个工具的主要功能是帮助开发者检测出项目中可能存在的jar包冲突。它的工作原理可能...
在Java开发过程中,jar包冲突是一个常见的问题,尤其是在大型项目或者依赖复杂的系统中。jar包冲突指的是多个不同的jar包中包含相同类的情况,这可能导致运行时错误或不可预测的行为。"jar包冲突检测工具"正是为了...
以下是一些关于如何检查和解决`jar`包冲突的关键知识点: 1. **冲突检测**: - **MANIFEST.MF检查**:每个`jar`包的`META-INF/MANIFEST.MF`文件可以列出其依赖项,通过比较不同`jar`包的`MANIFEST.MF`,可以初步...
在Java开发过程中,"jar包冲突"是一个常见的问题,它主要出现在项目中引用了多个库,而这些库可能包含了相同类的不同版本。这种情况可能导致运行时错误或者程序行为不一致,因为JVM在加载类时可能会遇到混淆。"检测...
通过调整类加载顺序为“类已载入并且先使用本地类装入器(父类最后)”,可以确保应用优先使用自身WAR包中的JAR包,从而避免版本冲突问题。 #### 扩展阅读 - **类加载机制**:深入了解Java的类加载机制对于理解和...
在将一个已经在Tomcat上正常运行的应用迁移到WebLogic时,可能会遇到各种问题,其中最常见的是配置问题和JAR包冲突。 标题"weblogic部署项目jar冲突解决"指出的核心问题是JAR包冲突。这是因为不同的应用服务器可能...
例如,MyEclipse自带的Mybatis版本可能较旧,而我们的项目可能需要使用更新的版本,这就可能导致类路径中有两个不同版本的相同Jar包,从而产生冲突。 解决此类问题的步骤如下: 1. **检查冲突**:首先,我们需要...
easyExcel支持最低的POI版本是3.17,现有项目若已用POI版本比这高的话,希望不改变现有的引用,解决jar包冲突的话,使用该独立版的jar包。该包已改过包名,亲测可兼容使用,网上有说把poi升级到4.1.2但是试了导出...
6. **使用jar包管理工具**:例如,使用FatJar或者One-Jar等工具,将所有依赖打包到一个可执行的jar中,避免运行时环境中的jar包冲突。 提供的"SSH整合JAR包"压缩文件,可能是为了方便开发者快速搭建SSH环境,包含了...
这个压缩包文件提供了工具和资源,帮助开发者修改jar包内的package包名,从而避免不同版本jar包之间的冲突。 核心工具是`jarjar-1.4.jar`,这是一个开源工具,专门用于重命名或移动Java类,以便在一个项目中整合多...
在项目开发过程中,我们可能会遇到多个版本的JSTL Jar包同时存在,导致版本冲突的问题。这个问题通常会影响到Web应用的正常运行,因此需要妥善解决。 首先,让我们来深入理解JSTL Jar包的作用。JSTL的核心标签库...
setting处理了,也将jar包的版本号都试了一遍,还是没解决,后来请教大牛,原来是没连网,maven工程加载了一部分jar包,连网之后自动下载的jar包跟之前的冲突,用这个脚本放在Maven仓库的目录,直接打开,可以将之前...
本资源"myeclipse2014配置好的注解包,Jar包没有冲突"旨在解决一个常见的开发问题:库文件(Jar包)的版本冲突。在Java开发中,尤其是使用MyEclipse 2014时,由于不同库可能依赖不同版本的其他库,导致版本冲突是很...
标题中的“asm.jar包冲突”指的是在开发或运行Java应用程序时遇到的问题,ASM是一个Java字节码操控和分析框架,常用于动态代理、字节码增强等场景。当多个库或者项目引用了不同版本的asm.jar,就可能出现版本冲突,...
jar包 jar包jar包 jar包jar包jar包jar包jar包jar包jar包 jar包jar包 jar包jar包jar包jar包jar包jar包jar包 jar包jar包 jar包jar包jar包jar包jar包jar包
解决jar包冲突的工具类jarjar-1.4.rar,jar包冲突解决方法,解决jar与jar冲突,jar与aar冲突,不想删除任何一个包,只能修改其中一个jar包包名即可解决,解决方法详细请看这篇文章: ...
jar 包冲突问题是在大型应用项目的开发中经常遇到的问题,它是由于不同的应用程序使用相同的共享 jar 包,但是这些 jar 包的版本不同所造成的。为了解决这个问题,我们需要了解 WAS 中类加载器的工作机制。 WAS 中...
在Java开发过程中,我们经常会遇到一个头疼的问题:jar包冲突。这是因为不同的库或者框架可能会包含相同类的不同版本,导致运行时出现错误。为了解决这个问题,开发者们开发了一款名为"jarjar"的工具,其核心功能是...