snakeyaml升级2.0及深入解析Java类加载机制的思考

项目场景:

漏洞修复及深入解析Java类加载机制的思考

安全漏洞修复,需要升级指定版本的jar,其中snakeyaml版本升级到2.0(吐血)
环境:内网环境+内网maven云仓库
springboot版本:2.6.3
默认snakeyaml版本:1.29

问题描述

需要升级指定版本的jar。使用原来springboot版本,只升级snakeyaml版本到2.0

  1. 在阿里云maven仓库没有2.0版本,手动拉取版本
  2. springboot2.6.3与snakeyaml2.0不兼容
    在这里插入图片描述

原因分析:

snakeyaml2.0与springboot2.6.3不兼容

解决方案:

在springcloud项目中,使用父pom管理子pom,在父pom中指定版本。

  • 1.下载指定版本依赖

  • 找到一台连接互联网的电脑**,手动拉取jar版本,打开maven仓库地址
    链接: link
    在这里插入图片描述

  1. 复制url

在这里插入图片描述

  • 在idea中,执行maven命令
 -`mvn dependency:get
  -DremoteRepositories=url 依赖的URL
  -DgroupId=groupId
  -DartifactId=artifactId
  -Dversion=version`
  • 在idea终端或者maven插件中输入

在这里插入图片描述

  • 替换刚才复制的链接、DgroupId等参数
mvn dependency:get   -DremoteRepositories=https://mvnrepository.com/artifact/org.yaml/snakeyaml/2.0   -DgroupId=org.yaml   -DartifactId=snakeyaml   -Dversion=2.0
  • 在本地maven中,打开路径:org.yaml,找到对应版本,复制到内网maven云仓库
    在这里插入图片描述
  • 在父pom指定snakeyaml2.0版本
	<snakeyaml.version>2.0</snakeyaml.version>
		...
     <dependencyManagement>
        <dependencies>
            <!-- snakeyaml版本 -->
            <dependency>
                <groupId>org.yaml</groupId>
                <artifactId>snakeyaml</artifactId>
                <version>${snakeyaml.version}</version>
            </dependency>
         </dependencies>
    </dependencyManagement>

2.启动项目报错问题处理利用 Java 父子加载器原理覆盖 jar 中类,保证一样的路径和类名
在这里插入图片描述

  • 把报错的类复制到common公共服务中,补充报错的构造方法。例如复制jar包的Representer,在common服务中创建一样的路径,把Representer放到该路径下
    在这里插入图片描述
    补充无参构造方法
 /**
     * 新增一个无参构造器
     */
    public Representer() {
        super(new DumperOptions());
        this.representers.put(null, new org.yaml.snakeyaml.representer.Representer.RepresentJavaBean());
    }
  • 报错2
Correct the classpath of your application so that it contains compatible versions of the classes com.fasterxml.jackson.dataformat.yaml.YAMLParser and org.yaml.snakeyaml.parser.ParserImpl
  • 依赖分析,redisson使用了snakeyaml,版本不兼容,一样处理方式

在这里插入图片描述
复制YAMLParser 类到公共服务中,处理报错的方法。因为1.29版本不用传LoaderOption对象,2.0+版本要传,故重载这个类
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

思考

在 Java 应用程序中,如果在类路径中存在相同的包路径和类名,那么 Java 虚拟机会根据类路径中的先后顺序加载类。通常情况下,类路径的顺序决定了哪个版本的类会被加载,这也是为什么你没有创建自定义类加载器,但还是能够覆盖原有类的原因

在 Java 类加载过程中,具体的加载行为取决于类加载器的类型以及类路径的配置。下面将详细解释类路径顺序和双亲委派模型的工作机制。

双亲委派模型

Java 的类加载器体系结构采用了双亲委派模型,其中类加载器层次分为三种主要类型:

  1. Bootstrap ClassLoader:负责加载 Java 核心类库,如 java.lang.* 等。
  2. Extension ClassLoader:负责加载扩展库中的类(JAVA_HOME/lib/ext)。
  3. Application ClassLoader:负责加载应用程序类路径(classpath)中的类。

类路径顺序

当一个类加载器需要加载一个类时,双亲委派模型规定它应首先委派给父加载器进行加载。如果父加载器无法找到该类,那么当前加载器才会尝试加载。如果类路径(classpath)配置中包含多个路径,那么类加载器会按照配置顺序逐个查找类文件。一旦找到匹配的类文件,它就会加载该类,而不会继续查找后面的路径。

具体工作流程

  1. 请求加载类:当应用程序请求加载一个类时,Application ClassLoader 会收到该请求。
  2. 委派给父加载器:Application ClassLoader 首先会将加载请求委派给它的父加载器,即 Extension ClassLoader。
  3. 继续向上委派:如果 Extension ClassLoader 也无法加载该类,则会继续向上委派给 Bootstrap ClassLoader。
  4. Bootstrap ClassLoader 尝试加载:Bootstrap ClassLoader 尝试加载核心类库中的类。如果成功,则返回类的引用。如果失败,则向下返回,允许 Application ClassLoader 尝试加载。
  5. Application ClassLoader 查找类路径:如果双亲加载器链都无法加载该类,Application ClassLoader 会按照类路径(classpath)顺序查找类文件。
  6. 找到类文件并加载:一旦 Application ClassLoader 在类路径中找到匹配的类文件,它会加载该类,并返回类的引用。不会继续查找后面的路径。

实际例子

假设类路径配置如下:

custom_classes:lib/library.jar

library.jar 中的类

// library.jar 中的 ExampleClass
public class ExampleClass {
    public void printMessage() {
        System.out.println("Original message from library.jar");
    }
}

custom_classes 目录中的类

// custom_classes/ExampleClass.java
public class ExampleClass {
    public void printMessage() {
        System.out.println("Custom message from custom_classes");
    }
}

编译自定义类并运行程序

javac -d custom_classes custom_classes/ExampleClass.java
java -cp custom_classes:lib/library.jar CustomClassLoaderTest

测试类加载的代码

public class CustomClassLoaderTest {
    public static void main(String[] args) {
        ExampleClass example = new ExampleClass();
        example.printMessage();
    }
}

运行结果

Custom message from custom_classes

总结

  • 双亲委派模型:类加载请求首先由父加载器处理,一直到 Bootstrap ClassLoader。
  • 类路径顺序:在类路径中配置多个路径时,Application ClassLoader 会按照顺序查找类文件。找到匹配类文件后立即加载,不会继续查找后续路径。
  • 覆盖机制:通过在类路径中优先放置自定义类路径,可以覆盖原有 jar 文件中的类。
  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值