前言
呵呵 最近碰到一些 老项目, 使用的传统的 libs 文件夹管理依赖, 显然存在的问题就是 jar 的依赖的问题
然后 之前呢, 也碰到了一些 依赖的相关问题
1. 异常:Class net.sf.cglib.core.DebuggingClassWriter overrides final method visit
2. tomcat启动内存堆栈溢出ASN1EncodableVector,DEREncodableVector循环依赖
我们这里来看的问题便是 "异常:Class net.sf.cglib.core.DebuggingClassWriter overrides final method visit"
继续往下看之前, 推荐看下这篇文章, classpath中存在多个jar存在同限定名的class classloader会如何加载
或者如果您足够了解 classpath中存在多个jar存在同限定名的class classloader会如何加载 这个问题的话, 也可以跳过
以下调试 java 层面的调试基于 jdk8
测试用例
新建一个 HelloWorld02 的 maven 项目, 新建测试用例如下
package com.hx.test;
import net.sf.cglib.core.DebuggingClassWriter;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
/**
* Test27ClassDuplicate
*
* @author Jerry.X.He <970655147@qq.com>
* @version 1.0
* @date 2021-05-22 10:25
*/
public class Test27DuplicateClass {
// Test27ClassDuplicate
public static void main(String[] args) throws Exception {
ClassLoader classLoader = new URLClassLoader(new URL[]{
new URL("file:///Users/jerry/.m2/repository/asm/asm/3.1/asm-3.1.jar")
});
DebuggingClassWriter obj1 = new DebuggingClassWriter(1);
Class clazz = classLoader.loadClass("net.sf.cglib.core.DebuggingClassWriter");
Constructor constructor = clazz.getDeclaredConstructor(int.class);
Object obj2 = constructor.newInstance(1);
System.out.println(" end ... ");
}
}
pom.xml 如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hx</groupId>
<artifactId>HelloWorld02</artifactId>
<version>0.0.1</version>
<properties>
<HXLog.version>0.0.2</HXLog.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
然后执行 Test27DuplicateClass 结果如下
问题的原因
同样是关于 classpath中存在多个jar存在同限定名的class classloader会如何加载 的问题
首先我们先看一下 net.sf.cglib.core.DebuggingClassWriter, 继承自 org.objectweb.asm.ClassWriter
然后我们搜索一下 org.objectweb.asm.ClassWriter, 我们会发现 asm-3.3.1.jar, asm-5.0.4.jar 里面均有 org.objectweb.asm.ClassWriter
然后我们查看一下 我们这里项目里面两个依赖的完整的信息, 依赖信息如下
可以看出的是 spring-cloud-starter-netflix-zuul 依赖了 asm-5.0.4.jar, 然后 cglib 依赖了 asm-3.3.1.jar
根据 classpath中存在多个jar存在同限定名的class classloader会如何加载 的规则, spring-cloud-starter-netflix-zuul 在运行的时候相关依赖是在前面, 因此加载 org.objectweb.asm.ClassWriter 的时候选择的是 asm-5.0.4.jar 中的 org.objectweb.asm.ClassWriter
而 net.sf.cglib.core.DebuggingClassWriter 里面是复写了 visit(int var1, int var2, String var3, String var4, String var5, String[] var6) 方法, 这个和 asm-5.0.4.jar 的 org.objectweb.asm.ClassWriter 的 public final void visit(int var1, int var2, String var3, String var4, String var5, String[] var6) 是不兼容的
master:HelloWorld02 jerry$ mvn dependency:tree
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=1024m; support was removed in 8.0
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------< com.hx:HelloWorld02 >-------------------------
[INFO] Building HelloWorld02 0.0.1
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ HelloWorld02 ---
[INFO] com.hx:HelloWorld02:jar:0.0.1
[INFO] +- org.springframework.cloud:spring-cloud-starter-netflix-zuul:jar:2.2.3.RELEASE:compile
[INFO] | +- org.springframework.cloud:spring-cloud-netflix-zuul:jar:2.2.3.RELEASE:compile
[INFO] | | +- org.springframework.cloud:spring-cloud-netflix-hystrix:jar:2.2.3.RELEASE:compile
[INFO] | | | +- org.springframework.boot:spring-boot-autoconfigure:jar:2.3.0.RELEASE:compile
[INFO] | | | \- org.springframework.boot:spring-boot-starter-aop:jar:2.3.0.RELEASE:compile
[INFO] | | +- org.apache.httpcomponents:httpclient:jar:4.5.12:compile
[INFO] | | | +- org.apache.httpcomponents:httpcore:jar:4.4.13:compile
[INFO] | | | \- commons-codec:commons-codec:jar:1.11:compile
[INFO] | | \- com.netflix.netflix-commons:netflix-commons-util:jar:0.3.0:compile
[INFO] | | \- javax.inject:javax.inject:jar:1:runtime
[INFO] | +- org.springframework.cloud:spring-cloud-starter:jar:2.2.3.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter:jar:2.3.0.RELEASE:compile
[INFO] | | | +- org.springframework.boot:spring-boot:jar:2.3.0.RELEASE:compile
[INFO] | | | +- org.springframework.boot:spring-boot-starter-logging:jar:2.3.0.RELEASE:compile
[INFO] | | | | +- ch.qos.logback:logback-classic:jar:1.2.3:compile
[INFO] | | | | | \- ch.qos.logback:logback-core:jar:1.2.3:compile
[INFO] | | | | +- org.apache.logging.log4j:log4j-to-slf4j:jar:2.13.2:compile
[INFO] | | | | | \- org.apache.logging.log4j:log4j-api:jar:2.13.2:compile
[INFO] | | | | \- org.slf4j:jul-to-slf4j:jar:1.7.30:compile
[INFO] | | | +- jakarta.annotation:jakarta.annotation-api:jar:1.3.5:compile
[INFO] | | | +- org.springframework:spring-core:jar:5.2.6.RELEASE:compile
[INFO] | | | | \- org.springframework:spring-jcl:jar:5.2.6.RELEASE:compile
[INFO] | | | \- org.yaml:snakeyaml:jar:1.26:compile
[INFO] | | +- org.springframework.cloud:spring-cloud-context:jar:2.2.3.RELEASE:compile
[INFO] | | | \- org.springframework.security:spring-security-crypto:jar:5.3.2.RELEASE:compile
[INFO] | | +- org.springframework.cloud:spring-cloud-commons:jar:2.2.3.RELEASE:compile
[INFO] | | \- org.springframework.security:spring-security-rsa:jar:1.0.9.RELEASE:compile
[INFO] | | \- org.bouncycastle:bcpkix-jdk15on:jar:1.64:compile
[INFO] | | \- org.bouncycastle:bcprov-jdk15on:jar:1.64:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-web:jar:2.3.0.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-json:jar:2.3.0.RELEASE:compile
[INFO] | | | +- com.fasterxml.jackson.core:jackson-databind:jar:2.11.0:compile
[INFO] | | | +- com.fasterxml.jackson.datatype:jackson-datatype-jdk8:jar:2.11.0:compile
[INFO] | | | +- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:2.11.0:compile
[INFO] | | | \- com.fasterxml.jackson.module:jackson-module-parameter-names:jar:2.11.0:compile
[INFO] | | +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.3.0.RELEASE:compile
[INFO] | | | +- org.apache.tomcat.embed:tomcat-embed-core:jar:9.0.35:compile
[INFO] | | | +- org.glassfish:jakarta.el:jar:3.0.3:compile
[INFO] | | | \- org.apache.tomcat.embed:tomcat-embed-websocket:jar:9.0.35:compile
[INFO] | | +- org.springframework:spring-web:jar:5.2.6.RELEASE:compile
[INFO] | | | \- org.springframework:spring-beans:jar:5.2.6.RELEASE:compile
[INFO] | | \- org.springframework:spring-webmvc:jar:5.2.6.RELEASE:compile
[INFO] | | +- org.springframework:spring-aop:jar:5.2.6.RELEASE:compile
[INFO] | | +- org.springframework:spring-context:jar:5.2.6.RELEASE:compile
[INFO] | | \- org.springframework:spring-expression:jar:5.2.6.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-actuator:jar:2.3.0.RELEASE:compile
[INFO] | | +- org.springframework.boot:spring-boot-actuator-autoconfigure:jar:2.3.0.RELEASE:compile
[INFO] | | | \- org.springframework.boot:spring-boot-actuator:jar:2.3.0.RELEASE:compile
[INFO] | | \- io.micrometer:micrometer-core:jar:1.5.1:compile
[INFO] | | +- org.hdrhistogram:HdrHistogram:jar:2.1.12:compile
[INFO] | | \- org.latencyutils:LatencyUtils:jar:2.0.3:runtime
[INFO] | +- org.springframework.cloud:spring-cloud-starter-netflix-hystrix:jar:2.2.3.RELEASE:compile
[INFO] | | +- org.springframework.cloud:spring-cloud-netflix-ribbon:jar:2.2.3.RELEASE:compile
[INFO] | | +- com.netflix.hystrix:hystrix-core:jar:1.5.18:compile
[INFO] | | +- com.netflix.hystrix:hystrix-serialization:jar:1.5.18:compile
[INFO] | | | +- com.fasterxml.jackson.module:jackson-module-afterburner:jar:2.7.5:runtime
[INFO] | | | +- com.fasterxml.jackson.core:jackson-core:jar:2.7.5:compile
[INFO] | | | \- com.fasterxml.jackson.core:jackson-annotations:jar:2.7.5:compile
[INFO] | | +- com.netflix.hystrix:hystrix-metrics-event-stream:jar:1.5.18:compile
[INFO] | | +- com.netflix.hystrix:hystrix-javanica:jar:1.5.18:compile
[INFO] | | | +- org.apache.commons:commons-lang3:jar:3.1:runtime
[INFO] | | | +- org.ow2.asm:asm:jar:5.0.4:runtime
[INFO] | | | +- org.aspectj:aspectjweaver:jar:1.8.6:compile
[INFO] | | | \- com.google.guava:guava:jar:15.0:compile
[INFO] | | \- io.reactivex:rxjava-reactive-streams:jar:1.2.1:compile
[INFO] | | \- org.reactivestreams:reactive-streams:jar:1.0.0:runtime
[INFO] | +- org.springframework.cloud:spring-cloud-starter-netflix-ribbon:jar:2.2.3.RELEASE:compile
[INFO] | | +- com.netflix.ribbon:ribbon:jar:2.3.0:compile
[INFO] | | | +- com.netflix.ribbon:ribbon-transport:jar:2.3.0:runtime
[INFO] | | | | +- io.reactivex:rxnetty-contexts:jar:0.4.9:runtime
[INFO] | | | | \- io.reactivex:rxnetty-servo:jar:0.4.9:runtime
[INFO] | | | \- io.reactivex:rxnetty:jar:0.4.9:runtime
[INFO] | | +- com.netflix.ribbon:ribbon-core:jar:2.3.0:compile
[INFO] | | | \- commons-lang:commons-lang:jar:2.6:compile
[INFO] | | +- com.netflix.ribbon:ribbon-httpclient:jar:2.3.0:compile
[INFO] | | | +- commons-collections:commons-collections:jar:3.2.2:runtime
[INFO] | | | +- com.sun.jersey:jersey-client:jar:1.19.1:runtime
[INFO] | | | | \- com.sun.jersey:jersey-core:jar:1.19.1:runtime
[INFO] | | | | \- javax.ws.rs:jsr311-api:jar:1.1.1:runtime
[INFO] | | | \- com.sun.jersey.contribs:jersey-apache-client4:jar:1.19.1:runtime
[INFO] | | +- com.netflix.ribbon:ribbon-loadbalancer:jar:2.3.0:compile
[INFO] | | | \- com.netflix.netflix-commons:netflix-statistics:jar:0.1.1:runtime
[INFO] | | \- io.reactivex:rxjava:jar:1.3.8:compile
[INFO] | +- org.springframework.cloud:spring-cloud-starter-netflix-archaius:jar:2.2.3.RELEASE:compile
[INFO] | | +- org.springframework.cloud:spring-cloud-netflix-archaius:jar:2.2.3.RELEASE:compile
[INFO] | | +- com.netflix.archaius:archaius-core:jar:0.7.6:compile
[INFO] | | | \- com.google.code.findbugs:jsr305:jar:3.0.1:runtime
[INFO] | | \- commons-configuration:commons-configuration:jar:1.8:compile
[INFO] | \- com.netflix.zuul:zuul-core:jar:1.3.1:compile
[INFO] | +- commons-io:commons-io:jar:2.4:runtime
[INFO] | +- org.slf4j:slf4j-api:jar:1.7.6:compile
[INFO] | \- com.netflix.servo:servo-core:jar:0.7.2:runtime
[INFO] | \- com.google.code.findbugs:annotations:jar:2.0.0:runtime
[INFO] \- cglib:cglib:jar:2.2.2:compile
[INFO] \- asm:asm:jar:3.3.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.723 s
[INFO] Finished at: 2021-05-29T18:51:28+08:00
[INFO] ------------------------------------------------------------------------
最终挂在了 defineClass 的过程中, 从 jar 中加载 class, 并校验的过程中
问题临时解决
1. 从依赖中排除不兼容的 jar, 比如这里的 spring-cloud-starter-netflix-zuul 下面的 asm
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.2.3.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
</dependencies>
2. 更新不兼容的两个 jar 的顺序, 让程序优先选择这个兼容的 asm-3.3.1.jar
<dependencies>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
</dependencies>
当然, 以上都是临时处理问题的方法, 要治标治本的话, 还是需要重构一下依赖
完
参考
classpath中存在多个jar存在同限定名的class classloader会如何加载