1、诊断包冲突
java.lang.NoSuchMethodError: org.apache.commons.io.output.DeferredFileOutputStream.<init>(ILjava/lang/String;Ljava/lang/String;Ljava/io/File;)V
2、解决
2.1 可见的依赖冲突
在eclipse中打开工程,在pom文件的dependency hierarchy中,搜冲突的包commons-io,查看各依赖包的依赖信息。包有依赖冲突的话,会有显示xxx版本与xxx版本冲突。选择正确的版本,将剩下的版本在对应的引用包下exclusion掉。
或者用 mvn dependency:tree > tree.log,将依赖信息导入文件tree.log中,查看包commons-io的依赖信息。
如果执行失败,报错:outofMemery
执行命令:
set MAVEN_OPTS=-Xmx512m -XX:MaxPermSize=128m
linux系统执行:
export MAVEN_OPTS="-Xmx512m -XX:MaxPermSize=128m"
然后再mvn dependency:tree > tree.log即可。
2.2 不可见的依赖冲突
1)查看服务器使用的jboss路径下有没有包含冲突的包的其他版本。
路径是:jboss-x.x.x.GA/lib, 和 jboss-x.x.x.GA/server/default/lib ,如果里面有冲突的版本,则删除。
2)查看异常发生时,JVM加载的是哪个包。
在程序启动的脚本中加入JVM启动参数 -verbose:class,然后重启应用。在启动日志中可以看到加载的类来自哪个包。
[Loaded org.apache.velocity.runtime.parser.node.ASTTrue from file:/home/admin/app/.default/deploy/app.war/WEB-INF/lib/velocity-1.6.4.jar]
如果在jboos的启动日志中没有发现加载冲突的类,可能是懒加载。
执行触发异常的操作,再看jboss的启动日志,这时就有加载类的信息了。
查看加载的类所在的包,与正确的包比较。
补充:
出现这种情况,有可能是包的版本引发的错误,所调用的方法在高版本和低版本的实现不一样,或者在某一版本中,方法有缺失。
也有可能是,两个不同的jar包,里面含有相同路径的类,然后在调用过程中混淆了。这种情况,可以在eclipse中使用shift+ctrl+T,查看工程中有多少个这样的类,查看类路径信息。
3)找到引发异常的包(比如A)之后,再回到工程里面,执行mvn dependency:tree > tree.log
在tree.log里面查找A包的依赖信息,然后在顶层包的依赖中排除掉A包即可。
demo,如果在依赖树中也没找到依赖信息。很可能是其他路径引入进来的(我不知道了。。),要解决的话,就要把A包全局排除掉,不要让它打进包中。
a.网上搜了一下,有一个maven插件,按照配置了一下,未果。
b.找到一个简单的方法,直接在父工程pom文件中加入此包的依赖,然后设置scope属性。
即:
<dependency>
<groupId>A.groupID</groupId>
<artifactId>A.artifactId</artifactId>
<version>1.2.7</version>
<scope>provided</scope>
</dependency>
c.在maven库中查找A包的其他版本,看看有没有空包版本,名字如not-exist等。然后再如工程pom中依赖此包。
maven添加依赖的时候,会优先加载高版本的jar包,如果依赖的这个包是空的,自然不会调里面的类或方法
关于scope,可以参考这个:http://supercharles888.blog.51cto.com/609344/981316
http://drizzlewalk.blog.51cto.com/2203401/665590 compile 默认范围,一直有用。
provided 编译时用,不会被打入jar包
runtime 编译的时候不需要,运行和测试的时候需要。
test 只在测试编译和测试运行时需要
system 需要制定一个本地路径,基于本地对象编译,不推荐使用。
唉,菜鸟之路……