写点什么

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:122691
用户头像

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

关注

评论

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

详解Camtasia的注释功能

淋雨

视频剪辑 Camtasia 录屏软件

分布式事务实战--一个完整的xa例子

叶东富

MySQL 数据库 分布式事务 Go 语言

模块8作业

方堃

流动性质押挖矿系统开发DAPP

获客I3O6O643Z97

DAPP智能合约交易系统开发 DeFi流动性挖矿 质押挖矿

剖析供应链攻击的防范

华为云开发者联盟

网络安全 安全 加密 供应链攻击 勒索软件

如何像百度直播一样优化用户体验(起播篇)

百度Geek说

大前端 直播 起播优化

汇总十家互联网大厂面试题后,产出Java架构师1575道“完美圣经”

Java架构追梦

Java 阿里巴巴 架构 面试

最新出炉!这份资料可帮你解决95%的问题

欢喜学安卓

android 程序员 面试 移动开发

IPFS挖矿靠谱吗?IPFS是什么项目是国家许可的吗?

Go 学习笔记之 Panic异常

架构精进之路

Go 语言 7月日更

EasyRecovery的工具栏介绍

淋雨

视频剪辑 Camtasia 录屏软件

ONES 对话敏捷专家王明兰|系统化敏捷转型,企业应该这样做

万事ONES

研发管理 解决方案 ONES 敏捷转型

基于深度学习的短文本相似度学习与行业测评

OPPO小布助手

深度学习 AI 短文本

什么是敏捷开发?敏捷开发的流程有哪些?

万事ONES

敏捷 敏捷开发 Agile ONES

最新整理:360°深入了解Flutter

欢喜学安卓

android 程序员 面试 移动开发

如何设计实现H5营销页面搭建系统

前端森林

架构 大前端 可视化 营销 React

最新美团点评Android团队面试题:你了解过移动端适配吗

欢喜学安卓

android 程序员 面试 移动开发

2021 EdgeX中国挑战赛拉开帷幕,赋能开发者,英特尔助力创新方案落地

E科讯

BTA挖矿软件平台系统开发

获客I3O6O643Z97

挖矿矿池系统开发案例 BTA 挖矿挣钱是什么原理

最新出炉!最新阿里+头条+腾讯大厂Android笔试真题

欢喜学安卓

android 程序员 面试 移动开发

走进Android架构!2021大厂Android面试经验

欢喜学安卓

android 程序员 面试 移动开发

融云主办WICC2021 即将召开 “音视频+AI”是新技术亮点

融云 RongCloud

企业如何选择合适的敏捷项目管理工具?

万事ONES

团队协作 研发体系 研发管理工具 ONES

模拟定位原理

BUG侦探

定位

坚持正确的研发项目管理转型之路

万事ONES

项目管理 DevOps 敏捷开发 ONES

学编程要考证么?我考了 6 个!

程序员鱼皮

Java c++ Python 数据结构 算法

号称下一代消息中间件!来看看它有多牛逼

白亦杨

Java

MindSpore模型精度调优实战:常用的定位精度调试调优思路

华为云开发者联盟

模型 mindspore 精度 模型精度调优 静态特征

你一定要知道的敏捷规划工具—影响地图

华为云开发者联盟

敏捷开发 软件开发 开发 影响地图 规划工具

面试官:数据库自增 ID 用完了会咋样?

一个优秀的废人

Java MySQL 数据库

11张图解单点登录系统,瑞斯拜特!

北游学Java

Java 单点登录

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