博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java.lang.NoSuchMethodError问题分析
阅读量:6813 次
发布时间:2019-06-26

本文共 4236 字,大约阅读时间需要 14 分钟。

hot3.png

一、问题引出:

今天在项目中,发现报了java.lang.NoSuchMethodError这个错误 ,错误信息如下:

Caused by: java.lang.NoSuchMethodError: com.google.common.base.Objects.firstNonNull(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
    at com.google.common.cache.CacheBuilder.getKeyStrength(CacheBuilder.java:529)

根据异常信息我们大概可以了解,工程中引用了一个名叫 com.google.common.cache.CacheBuilder 的类,并调用了其中名为 getKeyStrength 的方法,如下:

Strength getKeyStrength() {    return (Strength)Objects.firstNonNull(this.keyStrength, Strength.STRONG);}

该方法又调用了com.google.common.base.Objects.firstNonNull这个方法,但是系统在加载该方法时却表示没有找到该方法。在IDEA里面输入com.google.common.base.Objects这个类名出来了两个:

195029_k5Bx_3729778.png

点进去发现,guava-14.0.1的com.google.common.base.Objects类实现是有这个方法的,如下:

public static 
T firstNonNull(@Nullable T first, @Nullable T second) { return first != null ? first : Preconditions.checkNotNull(second);}

但是在google-collection-1.0.jar包中的com.google.common.base.Objects却没有这个实现,其内容如下:

package com.google.common.base;import com.google.common.annotations.GwtCompatible;import java.util.Arrays;import javax.annotation.Nullable;@GwtCompatiblepublic final class Objects {    private Objects() {    }    public static boolean equal(@Nullable Object a, @Nullable Object b) {        return a == b || a != null && a.equals(b);    }    public static int hashCode(Object... objects) {        return Arrays.hashCode(objects);    }}

得出结论,这是一个包冲突问题,

二、问题解决:

当遇到这类问题我们该如何解决呢,主要有以下三步:

1、 发现是哪个类发生了冲突:

前面已经分析过,是com.google.common.base.Objects这个类的冲突

2、发现冲突 jar 包,即冲突类存在于哪个 Jar 包中:

见前面分析,发现是google-collection-1.0.jar和guava-14.0.1.jar包冲突

3、发现这个冲突 Jar 包是自身系统直接引用的还是系统引用的 Jar 间接引用的:

第三步,我们看 google-collections-1.0.jar 是否是应用直接引用的。

通过查看这两个包的引用发现,工程里面直接引用了google-collections这个jar包,如下:

com.google.collections
google-collections

,没有发现直接引用guava.jar包,因此guava.jar包是通过其他jar包间接引用过来的。

我们的项目是通过 maven 进行引用 jar 包的管理。因此,结合 maven 的命令 mvn dependency:tree 可以发现这两个jar 包到底是通过哪些jar 包间接引用进来的。

       经查询资料发现,guava.jar包是google-collections的升级版,包括后者,所以去掉google-collections的包引入,重启工程,问题解决。

三、问题分析与拓展

      这类情况的发生很可能是因为如下状况引起的:随着业务需求的不断扩展,应用中代码量也会逐渐增长,工程中引用的二方包或者三方包也自然而然会越来越多。因此,不可避免,可能存在引用的二方包或三方包相互冲突所导致的系统问题。

一般通过如下方法,可以定位并决绝包冲突的问题:

1、mvn dependency:tree

这个命令可以输出所有的依赖,如果加入一些参数,可以过滤一些东西,如

-Dverbose

-Dincludes

-Dexcludes  等参数会能够帮助尽快定位问题

2、IDEA的jar包依赖分析,再次不再赘述

3、自己写一个测试类,来查看加载的到底是哪个jar包:

有时,你以为解决了,但是偏偏还是报类包冲突(典型症状是java.lang.ClassNotFoundException或Method不兼容等异常),这时你可以设置一个断点,在断点处通过下面这个我做的工具类来查看Class所来源的JAR包:
    package com.ridge.util;  
      
    import java.io.File;  
    import java.net.MalformedURLException;  
    import java.net.URL;  
    import java.security.CodeSource;  
    import java.security.ProtectionDomain;  
      
    /** 
     * : chenxh 
     * : 13-10-31 
     */  
    public class ClassLocationUtils {  
      
        /** 
         * 获取类所有的路径 
         * cls 
         *  
         */  
        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();  
        }  
      
    }  
随便写一个测试,设置好断点,在执行到断点处按alt+F8动态执行代码(intelij idea),假设我们输入:
Java代码  收藏代码
ClassLocationUtils.where(org.objectweb.asm.ClassVisitor.class)  
即可马上查出类对应的JAR了:
这就是org.objectweb.asm.ClassVisitor类在运行期对应的JAR包,如果这个JAR包版本不是你期望你,就说明是你的IDE缓存造成的,这时建议你Reimport一下maven列表就可以了,如下所示(idea):

4、有的时候可能是IDE的问题:

(1)Reimport一下,IDE会强制根据新的pom.xml设置重新分析并加载依赖类包,以得到和pom.xml设置相同的依赖。

(2)idea清除缓存,采用idea自带的功能,File->Invalidate Caches 功能直接完成清除idea cache

参考文献:http://fufeng.iteye.com/blog/1755167

http://blog.csdn.net/sun_wangdong/article/details/51852113

转载于:https://my.oschina.net/u/3729778/blog/1581781

你可能感兴趣的文章
vc++基础班[23]---文件夹的基本操作
查看>>
关于gnome
查看>>
LSPCI具体解释分析
查看>>
【AngularJS】—— 3 我的第一个AngularJS小程序
查看>>
FireFox 浏览器插件/扩展开发学习
查看>>
Groovy 与 Python 的差异【翻译】
查看>>
Theano学习笔记(一)——代数
查看>>
GO语言的开源库
查看>>
java中获取系统属性以及环境变量
查看>>
微信开发(03)之新建按钮时报错 errcode 40054
查看>>
TEA encryption with 128bit key
查看>>
操作系统定期定时执行python脚本
查看>>
TCP的拥塞控制
查看>>
FZU 1894 志愿者选拔 单调队列
查看>>
**app后端设计(10)--数据增量更新(省流量)
查看>>
用SoapUI进行Webservice的性能压力测试
查看>>
.NET反编译之manager,base.AutoScaleMode修复
查看>>
光看这图片就知道是大片--今天是五一劳动节尽管还是敲着代码(日常就是这样)然后想不出写什么了,也找不到好的素材,最后开心一下吧...
查看>>
希尔排序算法
查看>>
【Cocos2d-Js基础教学(3)各种基类的定义和使用】
查看>>