随着业务需求的不断扩展,应用中代码量也会逐渐增长,工程中引用的二方包或者三方包也自然而然会越来越多。因此,不可避免,可能存在引用的二方包或三方包相互冲突所导致的系统问题。
本文将针对前段时间遇到的实际案例进行分析,旨在当遇到包冲突问题时该如何解决,并提供同事用 python 写的一个发现包冲突的小工具(十分有用!)
一 发现问题:
首先 ,让我们看下异常,这是在应用启动后,执行具体操作时所报的错误:
Caused by: java.lang.NoSuchMethodError: com.google.common.collect.MapMaker.expireAfterWrite(JLjava/util/concurrent/TimeUnit;)Lcom/google/common/collect/MapMaker;
at com.taobao.treasure.client.TreasureClientImpl.<init>(TreasureClientImpl.java:31)
at com.taobao.treasure.client.TreasureClientFactory$1.getPipeline(TreasureClientFactory.java:95)
at org.jboss.netty.bootstrap.ClientBootstrap.co
nnect(ClientBootstrap.java:212)
at org.jboss.netty.bootstrap.ClientBootstrap.connect(ClientBootstrap.java:188)
at com.taobao.treasure.client.TreasureClientFactory$2.call(TreasureClientFactory.java:261)
at com.taobao.treasure.client.TreasureClientFactory$2.call(TreasureClientFactory.java:248)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
at java.util.concurrent.FutureTask.run(FutureTask.java:138)
at com.taobao.treasure.client.TreasureClientFactory.getClient(TreasureClientFactory.java:239)
... 53 more
根据错误我们大概可以了解,工程中引用了一个名叫 com.google.common.collect.MapMaker 的类,并调用了其中名为 expireAfterWrite() 的方法,但是系统在加载该方法时却表示没有找到该方法。
这是一个很明显的包冲突问题,这类情况的发生很可能是因为如下状况引起的:
如图,你引用了 2 个三方包 a.jar 和 b.jar , a.jar 中又引用了一个 c.jar ,假设 c.jar 的版本号为 version-1, b.jar 中也引用了 c.jar ,假设这里的 c.jar 相对于 a.jar 中的 c.jar 为较高版本,记为 version-2 , b.jar 中某个类引用了 c.jar 的类 classA 中的方法 method A() ,并且该方法只存在于高版本的 c.jar(version-2) 的类 classA 中,而不存在 c.jar(version-1) 的类 classA 中。
当系统编译加载时,系统可能编译加载 c.jar(version-1) ,也可能编译加载 c.jar(version-2) ,当编译加载 c.jar(version-2) 时,由于很多 jar 包都支持向下兼容,即高版本兼容低版本,因此不论 a.jar 调用 c.jar 还是 b.jar 调用 c.jar 一般都不会出问题。但如果此时刚好应用编译加载的是 c.jar(version-1) 中的类 classA 时,那么 b.jar 调用 Method A() 时便会报上述错误,因为 Method A() 函数只存在于高版本的 c.jar 中,而此时系统编译加载的却是低版本的 c.jar 。
二 解决问题
当遇到这类问题我们该如何解决呢 ? 主要有以下三步:
第一, 发现是哪个类发生了冲突;
第二, 发现冲突 jar 包,即冲突类存在于哪个 Jar 包中;
第三, 发现这个冲突 Jar 包是自身系统直接引用的还是系统引用的 Jar 间接引用的。
针对上述第一步,我们使一个 用 python 写的 名为 conflictdetect 小工具来解决。
将 conflictdetect.exe 下载后,存放到某个目录,然后将 conflictdetect.exe 的存放路径设定至环境变量 path 中,打开 CMD ,到 jar 包所在目录。
运行:
conflictdetect.exe
就会检测到目录中存在冲突的 jar 包,并以三种格式输出 ,: 只输出 jar ,只输出 class, 两个都输出。
通过 conflictdetect –h 可以查看用法。
本人将 conflictdect.exe 放置于 D:\exe.win32-3.2 下,因此在环境变量 Path 中设置的是 D:\exe.win32-3.2 ,打开 CMD ,定位到应用存放 jar 包的目录下,执行 :
conflictdetect.exe –t –f –o “D:/out.log”
此时,在 D 盘中将会发现一个名为 out.log 的文档,里面记录了存放 jar 包目录下所有冲突的 class 和 jar 。在其中我们 search 一把上述系统冲突的类名“ MapMaker ”,发现他们原来是存在于 google-collections-1.0.jar' 和 'guava-r09.jar' 中。 如下图:
org/springframework/remoting/jaxrpc/JaxRpcPortProxyFactoryBean.class=['spring-2.0.7.jar', 'spring-remoting-1.2.7.jar']
com/alibaba/service/uribroker/DefaultURIBrokerService.class=['toolkit-service-uribroker-1.0.jar', 'toolkit-webx-all-in-one-2.0.jar']
com/alibaba/service/pool/RecyclableSupport.class=['toolkit-service-pool-1.0.jar', 'toolkit-webx-all-in-one-2.0.jar']
com/google/common/collect/MapMaker$1.class=['google-collections-1.0.jar', 'guava-r09.jar']
org/springframework/core/task/SimpleAsyncTaskExecutor.class=['spring-2.0.7.jar', 'spring-core-2.0.6.jar']
此时,对系统有影响的冲突类和冲突 jar 包我们都已经发现了。
通过网上百度,原来 google-collections-1.0.jar 和 guava.jar 都 google 的产品,并且 guava.jar 是 google-collections-1.0.jar 升级版本,因此在编译过程中我们应该把 guava.jar 编译进工程,而不能把 google-collections-1.0.jar 编译进工程。
第三步,我们看 google-collections-1.0.jar 是否是应用直接引用的。经过确认,我的项目中并没有直接引用这两个 jar 包,因此可能是通过其他 jar 包间接引用进来的。由于项目中是通过 maven 进行引用 jar 包的管理。因此, 结合 maven 的命令 mvn dependency:tree 可以很容易发现这两个jar 包到底是通过哪些jar 包间接引用进来的。
+- com.know.diamond:diamond-sdk:jar:2.0.5:compile
[INFO] | +- net.sourceforge.htmlunit:htmlunit:jar:1.14:compile
[INFO] | | +- rhino:js:jar:1.6R7:compile
[INFO] | | +- nekohtml:nekohtml:jar:0.9.5:compile
[INFO] | | \- net.sourceforge.cssparser:cssparser:jar:0.9.4:compile
[INFO] | +- com.taobao.diamond:diamond-utils:jar:2.0.5:compile
[INFO] | | +- org.codehaus.jackson:jackson-core-lgpl:jar:1.4.0:compile
[INFO] | | \- org.codehaus.jackson:jackson-mapper-lgpl:jar:1.4.0:compile
[INFO] | \- com.google.collections:google-collections:jar:1.0:compile
原来是 diamond-sdk:jar 间接引用了 com.google.collections:google-collections:jar. 因此我们通知 diamond-sdk:jar 的维护者进行 jar 包升级,或者在 MVN 编译过程中强制禁止 google-collections:jar 编译进工程。如下:
<dependency>
<groupId>com.know.diamond</groupId>
<artifactId>diamond-sdk</artifactId>
<version>2.0.5</version>
<exclusions>
<exclusion>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
OK,重新编译工程,启动,问题解决。
分享到:
相关推荐
针对上述问题,可以采取以下步骤来解决包冲突问题: 1. **分析项目依赖**:首先需要使用Maven等构建工具的依赖分析功能来查看项目的依赖树,了解哪些库之间存在版本冲突。 - 在Maven中,可以通过执行命令`mvn ...
### 解决网上应用厅部署在WAS上JAR包冲突问题 #### 背景介绍 在企业级应用开发与部署的过程中,经常会遇到各种技术挑战,其中之一就是在WebSphere Application Server (WAS) 上部署应用程序时遇到的JAR包冲突问题。...
解决包冲突问题的方法有多种,下面我们将逐一介绍: 1. 使用endorsed目录 endorsed目录是Weblogic服务器提供的一个特殊目录,用于存放项目中的jar包。将jar包放入endorsed目录可以使得Weblogic服务器优先加载这些...
本文主要讨论了在 WebSphere Application Server(WAS)中解决 jar 包冲突问题的方法。jar 包冲突问题是在大型应用项目的开发中经常遇到的问题,它是由于不同的应用程序使用相同的共享 jar 包,但是这些 jar 包的...
"websphere下部署CXF项目jar包冲突问题解决方式"这一主题聚焦于如何在IBM Websphere Application Server (WAS)中成功部署包含Apache CXF Web服务的WAR包,解决由于类加载导致的运行异常。 Apache CXF是一个流行的...
在开发Java Web应用程序时,Spring和...通过以上步骤和策略,大多数Spring与Hibernate的包冲突问题都可以得到解决。在实际开发过程中,应始终关注框架的新版本和官方文档,以便获取最新的兼容性和最佳实践信息。
因与cxf包xmlschema-core-*.jar 冲突 故重新打包 XmlSchema-1.1.jar 源码修改原类径的方法来重新打包避免冲突 源码放在javas.rar文件夹中 org.codehaus.xfire.wsdl11.parser.SchemaInfo org.codehaus.xfire....
OSGi(Open Services Gateway Initiative)是一种模块化系统和Java服务框架,它允许在单个JVM上运行多个版本的相同库或服务,从而解决了不同版本jar包冲突的问题。本示例通过一个名为“myself”的工程,展示了如何...
"jar包冲突检测工具"正是为了解决这个问题而设计的。 这个工具的主要功能是帮助开发者检测出项目中可能存在的jar包冲突。它的工作原理可能是通过遍历指定路径下的所有jar文件,然后对比每个jar中的类文件,找出具有...
解决SSH集成jar包冲突的问题,首先需要对每个框架的jar包进行精简,只保留必需的部分。通常,这一步可以通过Maven或Gradle等构建工具来完成,通过设置正确的依赖管理和排除规则,确保每个jar包的版本和依赖关系得到...
解决 WebSphere 中的 jar 包冲突问题 在大型 Java 软件开发中,jar 包冲突问题是一个常见的问题,系统开发人员经常会为解决类似的问题耗费大量的时间进行调试和测试。为了解决这个问题,本文将从 WebSphere 中类...
实际开发中,可以采用多种方法来解决包冲突问题,比较常见的是类似 SpringBoot 的做法,统一管理应用所有依赖包的版本,保证这些三方包不存在依赖冲突。这种做法只能有效避免包冲突的问题,不能根本上解决包冲突的...
- **OSGi**:Open Service Gateway Initiative提供了一种动态的模块化系统,允许不同版本的类共存,从而解决了`jar`包冲突问题。 5. **冲突解决策略**: - **优先级选择**:根据业务需求和库的重要程度设定优先级...
为了解决这个问题,你可能需要删除或替换冲突的类。 具体解决jar冲突的方法通常包括以下步骤: 1. **排除冲突的类**:正如描述中所述,可以直接删除"commons-beanutils-1.7.0.jar"中的`org/apache/commons/...
当Weblogic启动遇到包冲突问题时,优先加载项目WEB-INF\lib目录下的包。 解决方案 解决该问题的方法是删除项目WEB-INF\lib目录下的wstx-asl-3.2.4.jar包,该包是Axis2使用的StAX API实现。删除该包后,Weblogic ...
在Java开发中,有时我们可能需要整合不同的框架或者库,比如Apache CXF和XFire,这两个都是用于构建Web服务的框架。...通过上述方法,开发者可以有效地解决这种类型的冲突问题,确保项目的稳定运行。
实际开发中,可以采用多种方法来解决包冲突问题,比较常见的是类似 SpringBoot 的做法,统一管理应用所有依赖包的版本,保证这些三方包不存在依赖冲突;这种做法只能有效避免包冲突的问题,不能根本上解决包冲突的...
标题"weblogic部署项目jar冲突解决"指出的核心问题是JAR包冲突。这是因为不同的应用服务器可能内置了不同版本的库,或者在类加载机制上有差异,导致原本在Tomcat上运行良好的应用在WebLogic上出现问题。以下是一些...