jar包冲突解决的一些经验

简介: 开篇  最近因为一些原因遇到了一些jar包冲突的实际问题,包括tomcat无法加载某lib包,hadoop上mr任务依赖lib版本问题,tomcat依赖包找不到等等。  这些问题归结起来能够很好的检验几个关键问题:1、双亲委派原则的理解;2、maven依赖传递的原则;3、java classpath路径先后顺序问题。

开篇

 最近因为一些原因遇到了一些jar包冲突的实际问题,包括tomcat无法加载某lib包,hadoop上mr任务依赖lib版本问题,tomcat依赖包找不到等等。

 这些问题归结起来能够很好的检验几个关键问题:1、双亲委派原则的理解;2、maven依赖传递的原则;3、java classpath路径先后顺序问题。


双亲委派原则

说明:

  • 1、首先,检查一下指定名称的类是否已经加载过,如果加载过了,就不需要再加载,直接返回。
  • 2、如果此类没有加载过,那么,再判断一下是否有父加载器;如果有父加载器,则由父加载器加载(即调用parent.loadClass(name, false);).或者是调用bootstrap类加载器来加载。
  • 3、如果父加载器及bootstrap类加载器都没有找到指定的类,那么调用当前类加载器的findClass方法来完成类加载。
public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
}

protected Class<?> loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loaded
        Class c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }
            } catch (ClassNotFoundException e) {
                // ClassNotFoundException thrown if class not found
                // from the non-null parent class loader
            }

            if (c == null) {
                // If still not found, then invoke findClass in order
                // to find the class.
                long t1 = System.nanoTime();
                c = findClass(name);

                // this is the defining class loader; record the stats
                sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                sun.misc.PerfCounter.getFindClasses().increment();
            }
        }
        if (resolve) {
            resolveClass(c);
        }
        return c;
    }
}

实际案列

  • 如果指定名称的类已经加载过了就不会再次加载,这个问题属于双亲委派范围,存在两种情况会遇到这个问题。
  • 1、多版本jar包依赖当中,由于低版本jar包中类已经加载导致高版本jar包中同名的类无法加载,从而导致使用了高版本的jar包依赖的函数无法找到,因为该函数只在高版本中存在。
  • 2、不同的jar包却存在同名路径的类,如package+class的路径是完全一致的,那就会导致两个不同的jar包的同名类只有一个类会被加载,从而同样找不到函数问题。


maven依赖原则

maven的依赖顺序

  • 1、依赖路径最短优先原则
    一个项目Demo依赖了两个jar包,其中A-B-C-X(1.0) , A-D-X(2.0)。由于X(2.0)路径最短,所以项目使用的是X(2.0)。
  • 2、pom文件中申明顺序优先
    如果A-B-X(1.0) ,A-C-X(2.0) 这样的路径长度一样怎么办呢?这样的情况下,maven会根据pom文件声明的顺序加载,如果先声明了B,后声明了C,那就最后的依赖就会是X(1.0)。
  • 3、覆写优先
    子pom内声明的优先于父pom中的依赖。

maven的解决冲突

  • 1、通过们mvn dependency:tree查看依赖树,通过maven的依赖原则来调整坐标在pom文件的申明顺序是最好的办法。
  • 2、通过exclude排除一些间接依赖,或者把依赖的jar包调整到最前面,按照maven加载顺序最前面加载了jar包后间接引用就不会生效了。


classpath路径先后问题

Of particular importance, and much consternation, 
the class loader will load classes in the order they appear in the classpath. 
Starting with the first classpath entry, 
the class loader visits each specified directory or archive file attempting to find the class to load. 
The first class it finds with the proper name is loaded, and any remaining classpath entries are ignored.

说明:

  • 上面说明了,java xx -classpath ".;a.jar;b.jar;" 时,如果a.jar和b.jar有重名的类,那么会以a.jar的为准,忽略b.jar的,因为jvm按照-classpath参数的路径先后顺序去load类,后续加载的同名的类会被忽略。

案例分享

  • hadoop集群上跑MR任务(自行打的jar包,jar包中依赖的protobuf-java版本高于hadoop集群自身lib目录当中的protobuf-java版本),导致每次先加载低版本的protobuf-java版本然后报方法找不到错误。
  • 实际当中针对上面的问题,会在把高版本的jar包放在当前目录并在代码当中把当前目录添加到classpath的最前面,保证先加载高版本的jar包。


tomcat无法加载jar包

真实案例

错误信息
 java.lang.NoClassDefFoundError: com/beibei/ai/base/UserModel

catalina.log日志内容
Apr 5, 2013 1:38:26 PM org.apache.catalina.loader.WebappClassLoader validateJarFile
INFO: validateJarFile(/home/frodo/apache-tomcat-7.0.37/webapps/hive/WEB-INF/lib/base-0.0.42-SNAPSHOT.jar) - jar not loaded. 
See Servlet Spec 2.3, section 9.7.2. Offending class: javax/servlet/Servlet.class

说明:

  • 查看/logs/catalina.log定位到具体的日志。
  • 和tomcat当中加载的类javax.servlet.Servlet发生冲突导致类无法加载。
  • Stack Overflow问题
目录
相关文章
|
6月前
|
Java Maven
maven依赖原则以及jar包冲突
该文介绍了Maven依赖原则:最短路径优先,申明顺序优先和覆写优先。当有冲突时,Maven选择路径最短的版本,按POM中声明顺序加载,并且子POM的依赖优先于父POM。解决冲突最佳方式是通过`mvn dependency:tree`检查依赖树并调整POM文件中的坐标顺序。
129 2
|
6月前
|
Java Maven
maven jar 包冲突处理
maven jar 包冲突处理
55 0
|
Java Maven
【异常解决】为什么会产生jar包冲突,如何排查jar包冲突?
【异常解决】为什么会产生jar包冲突,如何排查jar包冲突?
257 0
|
6月前
|
Java 应用服务中间件 数据库连接
hibernate+struts2整合jar包冲突
hibernate+struts2整合jar包冲突
|
Java Maven 开发者
又遇到maven jar包冲突了,如何快速解决
又遇到maven jar包冲突了,如何快速解决
194 0
|
Java Maven
不会还在为jar包冲突发愁吧
在我们平时的开发过程中,常常会遇到引入各种不同的 jar 包,然后引发的 Maven 依赖冲突,今天我们来学习下如何使用 Maven 命令检测 pom.xml 中的重复依赖项。
83 0
|
Java 应用服务中间件 数据库连接
hibernate+struts2整合jar包冲突
前几天,在用Hibernate+Struts2做项目的时候遇到了一个很棘手的问题,jar包冲突!!!先亮一下错误:
|
消息中间件 SQL 分布式计算
spark和kafka jar包冲突NoSuchMethodError: net.jpountz.lz4.LZ4BlockInputStream
在利用Spark和Kafka处理数据时,有时会同时在maven pom中引入Spark和Kafka的相关依赖。但是当利用Spark SQL处理数据生成的DataSet/DataFrame进行collect或者show等操作时,抛出异常NoSuchMethodError: net.jpountz.lz4.LZ4BlockInputStream
|
Java 应用服务中间件 数据库连接
Maven项目中jar包冲突问题解决 导入jar包scope作用域的使用
Maven项目中jar包冲突问题解决 导入jar包scope作用域的使用
285 0
Maven项目中jar包冲突问题解决 导入jar包scope作用域的使用

热门文章

最新文章

相关实验场景

更多
下一篇
无影云桌面