`
wangyujie0431
  • 浏览: 2657 次
社区版块
存档分类
最新评论

Maven 项目SuchNoMethod等报错

阅读更多
对于maven项目经常会出现,项目引入一堆依赖,最后项目运行的时候出现

NoSuchMethod

ClassNotFound

NoClassDefFound

这些exception,这个时候就要怀疑是不是引包的姿势不对,导致了项目启动出现问题!

Root Cause:

一般出现以上exception的根本原因是,a,b不同的依赖之间依赖了同一个依赖c的不同版本,在A版本中某个类还在,但是在B版本中对应的类已经被删除了,maven依赖的时候根据自身的规则依赖了B版本,导致了应用在调用a的方法时,出现了NoSuchMethodException


ps:这里稍微提一下maven的依赖加载机制,我们都知道classloader是根据全路径名去加载一个类的,所以maven在依赖jar包时不可能对同一个jar包依赖多次,maven在加载jar时会根据加载的依赖复杂度去决定加载哪一个版本依赖,例如应用-->A-->B-->C(1.0.2), 应用-->D-->C(1.0.1),maven在向项目导入依赖的时候只会导入C(1.0.1),因为其依赖的复杂度(层数)比较低;那如果出现复杂度一样的情况,maven又是怎么做的呢,maven会根据pom文件中的顺序导入依赖,比较靠前的先导入


下面我们来人工模拟下NoSuchMethodException的出现情况:
首先是底层依赖的包,对应root cause中提到的c

/**
 * Created by Roy on 16/9/11.
 */
public class DependencyBeanB {

    public void dependMethodA(){
        System.out.println("You depend on method A");
    }

//    public void dependMehtodB(){
//        System.out.println("You depend on method B");
//    }

}


maven install 到本地仓库 版本是1.0.1

/**
 * Created by Roy on 16/9/11.
 */
public class DependencyBeanB {

//    public void dependMethodA(){
//        System.out.println("You depend on method A");
//    }

   public void dependMehtodB(){
        System.out.println("You depend on method B");
    }

}


maven install 到本地仓库 版本是1.0.2

二层依赖,对应root cause中提到的a
/**
 * Created by Roy on 16/9/11.
 */
public class SecondInvokerA {

    public void invoke(){
        DependencyBean dependencyBean = new DependencyBean();
        dependencyBean.dependMethodA();
    }

}


<dependencies>
        <dependency>
            <groupId>com.roy</groupId>
            <artifactId>maven-test-jar</artifactId>
            <version>1.0.1</version>
        </dependency>
    </dependencies>


对应root cause 中提到的b
/**
 * Created by Roy on 16/9/11.
 */
public class SecondInvokerB{

    public void invoke(){
        DependencyBean dependencyBean = new DependencyBean();
        dependencyBean.dependMehtodB();
    }

}


<dependencies>
        <dependency>
            <groupId>com.roy</groupId>
            <artifactId>maven-test-jar</artifactId>
            <version>1.0.2</version>
        </dependency>
    </dependencies>


应用
public class DependencyInvoker {

    public static void main(String[] args) {
        System.out.println("Invoker main method invoke.");
        SecondInvokerB secondInvoker = new SecondInvokerB();
        secondInvoker.invoke();
    }
}


<dependencies>
        <dependency>
            <groupId>com.roy</groupId>
            <artifactId>depend-project-a</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>

        <dependency>
            <groupId>com.roy</groupId>
            <artifactId>depend-project-b</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

运行应用 错误出现:
Invoker main method invoke.
Exception in thread "main" java.lang.NoSuchMethodError: com.roy.test.DependencyBean.dependMehtodB()V
at com.roy.SecondInvokerB.invoke(SecondInvokerB.java:12)
at com.roy.DependencyInvoker.main(DependencyInvoker.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

知道了是由于重复依赖导致了问题,我们就要解决问题了

两种方式,
一,通过http://maven.apache.org/plugins/maven-dependency-plugin/ 插件在项目未运行前就发现问题,防患于未然
二,如果没有依赖这个插件,问题发生了怎么办,方法一,可以借助IDE的依赖图找到重复依赖,然后exclude掉(实际项目中出现方法,类找不到一般都是传递依赖了版本较低的包,跟以上举的例子不太一样),方法二,通过mvn dependency:tree -Dverbose 命令直接找到被忽略依赖的包,然后exclude掉出现问题jar(一般都是引入低版本包出的问题,因为高版本的包一般都会做向下兼容)

[INFO] Building maven-classload 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ maven-classload ---
[INFO] com.roy:maven-classload:jar:1.0-SNAPSHOT
[INFO] +- com.roy:depend-project-a:jar:1.0-SNAPSHOT:compile
[INFO] |  \- com.roy:maven-test-jar:jar:1.0.1:compile
[INFO] \- com.roy:depend-project-b:jar:1.0-SNAPSHOT:compile
[INFO]    \- (com.roy:maven-test-jar:jar:1.0.2:compile - omitted for conflict with 1.0.1)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.782 s
[INFO] Finished at: 2016-09-11T22:27:21+08:00
[INFO] Final Memory: 11M/155M
[INFO] ------------------------------------------------------------------------

红色部分指出,当前依赖的jar被另一个版本的取代了,这个时候你就要根据实际情况exclude掉一个
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics