深入剖析 Java 新特性
范学雷
前 Oracle 首席软件工程师,Java SE 安全组成员,OpenJDK 评审成员
16539 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 23 讲
深入剖析 Java 新特性
15
15
1.0x
00:00/00:00
登录|注册

17 | 模块系统:为什么Java需要模块化?

你好,我是范学雷。今天,我们一起来讨论 Java 平台模块系统(Java Platform Module System,JPMS)。
Java 平台模块系统是在 JDK 9 正式发布的。为了沟通起来方便,我们有时候就直接简称为 Java 模块。Java 平台模块系统,可以说是自 Java 诞生以来最重要的新软件工程技术了。模块化可以帮助各级开发人员在构建、维护和演进软件系统时提高工作效率。软件系统规模越大,我们越需要这样的工程技术。
实现 Java 平台的模块化是具有挑战性的,Java 模块系统(Module System)的最初设想可以追溯到 2005 年的 Java 7,但是最后的发布,是在 2017 年的 JDK 9。它的设计和实现,花了十多年时间,我们可以想象它的复杂性。
令人满意的是,Java 平台模块系统最终呈现的结果是简单、直观的。我们并不需要太长的时间,就能快速掌握这一技术。
我们先来了解 Java 模块化背后的动力,和它能够带来的工程效率提升。除非特别说明,这一次的讨论,说的都是 JDK 8 及以前的版本的事情。下一次,我们再来讨论 JDK 9 之后,我们应该怎么使用 Java 平台模块系统。

缺失的访问控制

我们都清楚并且能够熟练地使用 Java 的访问修饰符。这样的访问修饰符一共有三个:public、protected,以及 private。如果什么修饰符都不使用,那就是缺省的访问修饰符,这也算是一种访问控制。所以,Java 语言一共定义了四种类型的访问控制。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Java平台模块系统(JPMS)是Java 9中引入的重要新技术,旨在提高软件系统的构建、维护和演进效率。文章指出了Java早期版本中存在的访问控制缺失,即缺乏包之间的定向私密通道,导致公开接口的实现代码对所有人开放的问题。此外,Java缺乏强制性的内部接口使用规范,使得内部接口的不合规使用成为Java版本升级的重要障碍。另外,Java的手工依赖管理问题也给应用程序部署带来了问题。这些问题对Java语言可维护性和部署复杂性产生了影响,现有解决方案依赖人工的风险。因此,Java平台模块系统的引入是为了解决这些问题,提高Java语言的可维护性和部署效率。JPMS的引入解决了Java语言包之间依赖关系的缺失,提高了应用启动效率,解决了影子类和版本冲突等问题。文章还提到了Maven、Gradle等工具如何解决依赖关系缺失的问题。总体来说,JPMS的引入为Java语言带来了新的思路和解决方案,提高了软件系统的构建、维护和演进效率。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入剖析 Java 新特性》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(6)

  • 最新
  • 精选
  • 第二少
    Maven、Gradle是怎么解决依赖关系缺失这样的问题的? 首先,这些工具都只能在jar包的粒度来解决依赖关系,而无法达到java package的粒度,当然你可以通过刻意的设计,比如一个jar包里只有一个package,来变相的达到java package级别,这些工具的打包方式也非常灵活,就算要一个jar包里只有一个package,也不需要在源码的组织上做到一个project只有一个package,源码仍然可以都放在一个project,打包时可以打多个jar包; 然后再来回答这个问题,maven的解决方案是: 1. 通过一个构建描述文件(pom.xml)来描述jar之间的依赖关系; 2. 通过给每个<dependency>定义<scope>来限制一个jar的作用域(是编译时可用,还是只在运行时可用,还是只有测试用例代码可用); 3. 通过内建的一些原则(如“最短路径原则”)以及外部的可自定义的dependencyManagement来解决版本/作用域冲突; 4. 通过各种打包插件来灵活打包jar gradle的解决方案跟maven类似,不过gradle支持更灵活的构建描述文件,这正好也是maven的很大短板;gradle支持使用groovy和kotlin作为dsl来写构建描述文件,groovy和kotlin是完备的编程语言,其表达能力跟xml比那就强太多了,写起来也简洁太多; 不过这一点也是双刃剑,maven内建了“构建生命周期”,所有的构建过程都必需在这套生命周期的框架之内,即便你自己写一个maven plugin,也必须把你自定义的goal绑定到maven的生命周期上去,无法随意修改构建顺序、构建步骤,也就规范了构建描述文件的写法,不会出现一千个人有一千种写法;而gradle就没有强制遵守的生命周期,限制就放开了,加上用编程语言来写构建描述文件,能玩的花活就多了,只要你愿意,你可以在构建描述文件里编程实现复杂的自定义构建流程,这在maven里通常需要用java写一个maven plugin来实现(甚至都未必能实现,因为maven有生命周期需要强制遵守)

    作者回复: 学到新东西了,谢谢🙏。

    2022-01-12
    14
  • 娄江国
    通过Maven管理依赖,会存在依赖传递导致的版本冲突问题。 如: 1、我的工程为ProjectMain,依赖了ProjectA和ProjectB; 2、ProjectA依赖了ProjectC,依赖的ProjectC的版本为1.0; 3、ProjectB依赖了ProjectC,依赖的ProjectC的版本为2.0; 4、启动ProjectMain时,只会加载1版本的个ProjectC。 可能会出现下面问题(假如加载的是ProjectC的1.0版本): 1、如果ProjectB调用了ProjectC的2.0版本中的新增方法,则运行时会抛出NoSuchMethodError的异常; 2、如果ProjectB调用的ProjectC的2.0版本中的方法签名,在ProjectC的1.0版本中都有,但内部实现做了修改,这样实际执行时,还是按ProjectC的1.0版本的逻辑执行,不符合ProjectB的目的。

    作者回复: 谢谢分享!

    2021-12-28
    2
    2
  • ABC
    另外,JDK9之后模块化这种并不是强制的,可以通过添加VM参数放开限制(--illegal-access=permit)。 例如: 放开之后,在运行时可以通过反射修改String类的value数组,达到动态修改String值的目的。

    作者回复: 是的,还是需要考虑兼用性的问题。

    2021-12-27
  • ABC
    平常用Maven,在集中管理方面做的很好。比如找一个库,只需要在Maven仓库中搜索,并添加XML配置到项目即可。在依赖加载方面也有很多镜像可以使用。 不足的是,不同依赖的不同版本可能会导致一些未知的问题。而Spring Boot Starts刚好就解决了这个问题。

    作者回复: 谢谢经验分享!

    2021-12-27
    2
  • ifelse
    学习打卡
    2022-10-14归属地:浙江
  • Jxin
    先回答问题 其实现在都有工具,所以包冲突这个事比以前好排太多了。但是依旧需要人工,只要没有自动化,就依旧会有效率问题和风险。 这篇开头我就有个痛点,虽然增加包维度控制的解决方案能解我的痛点,但看样子并不能很快支持。 我的痛点是,包范围的访问权限缺少对子包的访问权限。这就导致我要么摊平,所有类都放在这个包目录下;要么就都只能用开放的访问权限。这对于有点洁癖想要分包结构整理类的我实在是种折磨。 类权限的发散也是项目腐化的源头,放现在看,能不能说他是个bug? 这个痛点我觉得其实不难解,如果不用增加包维度访问控制这个解决方案的话。 那么临时方案可不可以?定义好修饰符实现对于使用方又无感,后面长期方案上了,完全可以平滑过度。
    2021-12-31
收起评论
显示
设置
留言
6
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部