写点什么

Jigsaw 项目会解决 Java 的 JAR 地狱问题么?

  • 2015-12-31
  • 本文字数:2011 字

    阅读完需:约 7 分钟

Nicolai Parlog 是一位热情的软件工程师,数字版权与开源软件的狂热拥护者;他对 AssertJ、ControlsFX、FindBugs 及 Property Alliance 等项目都做出过重要的贡献。近日,Parlog 就 Jigsaw 项目撰写了一篇文章,谈到了 Jigsaw 项目的一些不足以及改进之处。Jigsaw 项目有着雄心勃勃的宏伟目标,其目标之一就是彻底摆脱极易出错且问题多多的类路径机制中的 JAR 地狱问题。不过,虽然该项目的其他目标会在不久的将来得以实现,但解决 JAR 地狱问题这一目标似乎并不是那么容易的。

为了更好地理解我们接下来要讨论的内容,首先来看一下 JAR 地狱问题,接下来介绍 Jigsaw 项目将会解决问题的哪些方面,以及为什么说 Jigsaw 所尝试解决的问题并不会对整个问题域产生本质的影响。最后,我们来看一下官方对于这个话题的立场,并给出如何防止出现模块地狱的提案。

JAR 地狱问题

JAR 地狱存在着如下循环问题:

  • 表述不清以及传递性依赖
  • 遮蔽
  • 版本冲突
  • 复杂的类加载

根据构建工具与组件系统(JDK 开发者称之为容器)为我们所带来的诸多功能与特性,我们可以认为表述不清以及传递性依赖问题已经在很大程度上得到了解决,遮蔽问题至少得到了缓解,而复杂的类加载也不再是老生常谈的问题了。这样,版本冲突就成为 JAR 地狱中最为严重的一个问题了,它影响到了很多很多项目每天的更新决策。

Jigsaw 将会带来哪些改变?

我之前曾就 Jigsaw 项目会为 Java 9 带来哪些新特性专门写过文章进行过介绍,不过这里将从不同的视角进行阐述。首先,它会受到当前的早期访问构建版的影响;其次,我们这里只从与 JAR/ 模块地狱相关的角度进行介绍。

Jigsaw 为 Java 带来的核心概念就是模块化。简而言之,模块就像 JAR 一样,同时带有一些附加信息与特性。这些信息包含了模块的名字以及模块所依赖的其他模块的名字。

依赖

当编译器与 JVM 在处理模块时,他们会解析这些信息。在编译或启动时,他们会通过模块路径传递性解析所有依赖。总体来说,这类似于类路径扫描,不过现在寻找的是整个模块而非单个类,对于 JVM 来说,这是在启动期而非运行期进行的。如果在模块路径上无法找到所有依赖,那么解析模块的传递性依赖就会失败。这显然可以解决表述不清,以及无休止的传递性依赖的问题。我认为这是个很棒的做法,Java 语言现在正式知道关于依赖的信息了,所有工具(编译器与 JVM 等)都能理解这一点并正常使用!不过,我认为这并不会对开发者每天的工作产生多少积极的影响,因为现在很多既有的基础设施都已经解决这个问题了,比如说构建工具等。

遮蔽

Jigsaw 消除了遮蔽的问题。模块系统可以确保每个依赖都会被另一个模块所实现,每个模块都会读取至多一个模块,定义了同名包的模块之间并不会相互干扰。更准确地说,模块系统在遇到模糊不清的情况时就会终止并报错,比如说两个模块将相同的包导出到相同模块中。

版本冲突

我们认为第三方库的版本冲突是 JAR 地狱最为难以解决的问题。最直接的解决方案就是一个模块系统能够加载同一个模块的不同版本。这需要确保这些版本之间不存在互相交互的情况。问题在于:在单个配置中,没必要支持一个模块的多个版本。实际上,当前的构建既不会创建,也无法理解模块版本信息。曾有人使用了一些变通办法。最丑陋,同时也是最可行的办法就是重命名出现冲突的构件,这样他们就不再是相同模块的两个不同版本了,而是两个完全不同的模块。不过,这种做法最后证明也是行不通的。显然,确保“定义了同名包的模块之间不会相互干扰”是在两个模块导出相同包时拒绝任何启动配置来实现的。即便没有模块读取他们亦如此!

复杂的类加载

模块与类加载器之间如何交互以及如何改变类加载的复杂性是个很棘手的问题。实际上,模块系统对模块与类加载器之间的关系并没有做多少限制。类加载器可以从一个模块或是多个模块来加载类型,只要模块之间不存在相互干扰的情况,并且每个模块中的类型只由一个加载器加载即可。因此,类加载器与模块之间是一对多的关系。

模块地狱?

既然依赖与遮蔽问题已经得到了解决,并且类加载问题也得到了改进,那我为何还要讨论模块地狱呢?就是因为版本冲突么?没错!如果 Jigsaw 想要解决 JAR 地狱问题,它就需要特别注意版本冲突问题。否则,很多项目并不会出现什么起色。他们依然要面对版本冲突问题,并且会陷入到自定义类加载器的梦魇中。

提案

我的提案是让开发者与构建工具能够传递一些额外的信息,这些信息能够解决一些含糊不清的问题。传递这种信息的两种常见方式是命令行与配置文件。如果使用命令行参数,那么每次启动时都需要输入一次。根据信息的多少以及项目的规模,这种做法可能会变得非常乏味。可以通过构建工具来创建配置文件,然后再通过命令行指定配置文件。这看起来是个不错的解决方案。目前,初始模块与所有的传递性依赖都是通过单个配置来解析的,这形成了单独的一个层次。不过,我们可以在运行期将相同模块的多个版本加载到不同层次中,这正是组件系统要做的事情。总的来说,我的建议就是通过多个层次来显式指定配置。

2015-12-31 02:122780
用户头像

发布了 88 篇内容, 共 272.7 次阅读, 收获喜欢 9 次。

关注

评论

发布
暂无评论
发现更多内容

保姆级教程,小白也能2周搞定3个月的Web开发任务!

博文视点Broadview

这一次!我在百度告诉你,当你请求百度时都发生了什么...

程序员 架构 面试 计算机

模块六作业

燕燕 yen yen

架构实战营

最佳实践 | 单元测试+回归测试在SRS代码提交中的实践总结

腾讯云音视频

SRS

课程排课软件开发

(王经理)专业app小程序开发

ipfs矿机怎样选?ipfs矿机多少钱一台?

分布式存储 IPFS ipfs挖矿 ipfs矿机 filecoin挖矿

Alibaba新产!Spring+SpringBoot+SpringCloud全家桶进阶小册

Java~~~

Java spring 架构 面试 Spring Cloud

Shopee物流业务核心数据库架构演变——权衡取舍的艺术

Shopee技术团队

架构 #数据库 #物流 #供应链 #Shopee

APP DIFF自动化解决方案

爱奇艺技术产品团队

测试 开发 精准测试 Diff i技术会

小数据与业务的毛细血管

boshi

大数据 深度思考

培训教育系统开发

(王经理)专业app小程序开发

AI自助帮你换背景,超强实时人像扣图算法开源啦!

百度大脑

人工智能

ZEGO 教程 | RTC + AI 视觉的最佳实践(移动端)

ZEGO即构

AI RTC 滤镜

终于有人把操作系统,CPU,基础知识,网络一次讲清楚了,绝绝子

Java~~~

Java 架构 面试 TCP 网络

常用正则表达式最强汇总(含Python代码举例讲解+爬虫实战)

Python研究者

8月日更

秋招开局痛击!迷惑的阿里三面反手一个感谢信,最终被字节捞起

编程susu

Java 编程 面试 计算机 技术宅

如何支持亿级用户分流实验?AB实验平台在爱奇艺的实践

爱奇艺技术产品团队

测试 开发 精准测试 AB testing实战

你还在认为TypeScirpt 是 AnyScript ?

程序员海军

typescript 大前端 javascri

👊【SpringCloud技术专题】超级详细的Gateway网关的技术指南

码界西柚

网关 SpringcloudGateway SpringCloud Gateway 8月日更

开源应用中心|这款纯手工打造的开源博客平台,大佬们都在用!

开源

今天我们来谈谈Golang的同步等待组

Regan Yue

Go 语言 8月日更 同步等待组

比POSTMAN更好用!在国产接口调试工具APIPOST中使用Mock

Proud lion

大前端 后端 Postman 开发工具 接口文档

使用接口文档快照机制,让接口文档不在频繁变动

CodeNongXiaoW

大前端 测试 后端 接口文档

ipfs矿机怎么买?ipfs矿机怎么获取?

ipfs矿机怎么买 ipfs矿机怎么获取

ARM工控主板比X86工控主板好吗?

双赞工控

是的你没看错,HTTP3来了

程序那些事

HTTP 程序那些事 http3

字节再次出圈!GitHub上爆火一星期的算法刷题手册竟出自这人之手

Java~~~

Java 架构 面试 算法 数据结构与算法

基于 Formily 的表单设计器实现原理分析 ​

全象云低代码

JavaScript 低代码开发 表单设计

算法推荐规制!《互联网信息服务算法推荐管理规定(征求意见稿)》公开征求意见

郑州埃文科技

开源大数据Meetup回顾 | 第四范式:现代存储架构下的系统优化实践

仓储管理系统开发介绍

(王经理)专业app小程序开发

Jigsaw项目会解决Java的JAR地狱问题么?_Java_张龙_InfoQ精选文章