一. 前言
本来是想写 JDK21 对比 JDK8 的差异的 ,但是第一个功能点就卡壳了,模块化系统还有点难搞,搞了一早上都没跑通,也不理解这样的目的
本来想随便丢个案例上去算了 ,但是这样太不负责了,所以专门出一篇来详细的学习一下。
案例很简单 ,但是目的在于 : 模块化的目的是什么?
二. 项目案例
2.1 基础项目结构
其实整个项目很简单 ,标志性的文件只有一个 : module-info.java . 这个文件可以手动创建,也可以通过 IDEA 菜单创建 👇👇👇
// modulea 的 module-info.java
// 此处通过 requires 表示自己依赖模块 moduleb
module com.example.modulea {
requires com.example.moduleb;
}
// moduleb 的 module-info.java
// 此处导出模块 moduleb
module com.example.moduleb {
exports com.example.moduleb;
}
❗ 到了这里 ,其实基础案例就已经完成了 。不需要执行什么就可以通过运行 mian 方法触发调用 :
- 和单项目的调用一样,哪怕在两个体系里面 ,
确实做到了相互的调用
- 可以通过 module-info.java 更精准的 require 引用 ,让自己的依赖更加清晰
三. 一点小探讨
3.1 模块化系统是什么
模块系统在 JDK9 中引入 ,目的是提高代码结构和可维护性。类似于 JS 里面写 Module + export 的方式 ,在 Package 上层再次做了一次功能的划分
。从其定位上的目的是为了保证更好的封装。
- 简单来说 : JAR > Module > Package > Class
❗❗❗ 但是你如果是 JavaWeb 和 Maven 的老手 ,就会发现这东西其实和 Maven 处理 dependency
差不多呀。
确实对于 Web 应用(Maven/Gradle)来说 ,通常已经通过 Maven 实现了 Module 的划分,我个人认为通常是没有必要再划一层
。
但是不要写了太久 Web 弄混淆了 ,Java 并不是只有一个 JavaWeb , 我认为模块化的 最佳场景 是为了更底层而服务的
. 例如 JDK 通过模块化 ,让自己被划分为多个不同的小模块。 这就意味着: 在特殊的低配场景 ,JRE 可以更小。
3.2 那么来到第二个问题 ,它实际的应用场景又是什么?
对于 Web 应用 ,我感觉上手不容易,跨越不小。 基于这种疑惑 ,我专门查阅的相关资料 :
- 模块化系统发起主要由于 JDK 太大 ,无法在小型设备上运行 ,所以把 JDK 拆开成 Module ,只选择需要的功能发布在小型设备上。
- 而对于一些部署在特殊机器上面的系统 ,可以通过模块化系统一层自己不想要的组件 ,同时添加自己需要的 module。
- 也就是说 ,项目的组成更自由了,它更偏向于底层 ,比如 C++ 写的一些自定义的工具。
- 而这种写法 ,自然被衍生出来可以使用 ,但是Web业务能用的场景不多。
基于模块化的特性 , JDK8 以后 JDK 取得了很大的发展 :
JDK 更小了
,传 JRE11 比 JRE8 小了一半 ,也可以有效的控制 JRE 内部的依赖
- 兼容性更好了 ,通过 exports
让真正的接口才会暴露在外面
,内部接口内部聚合封闭。(❗确实有好处,工具代码更安全,不用担心各种冲突) - 迭代可以更加频繁 ,
就像微服务一样 ,边界小了,体积小了,开发起来也可以更好的控制影响范围
👉 总结 : 如果用模块化来写 JDK 基础组件或者工具 ,确实会很香。
四. 回顾一下和 Maven 到底有什么异同?
看到这里感觉模块化更适合底层 Java 的使用 (不要把自己的关注局限到 Web ,Maven ,Spring 那里)。更适合对一些源码工具进行模块化。
再和 Maven 对比下可以发现 :Maven 更像对业务的划分,其本身对于代码的边缘控制并不强 ,引入了一个 Maven, 那么 Maven 里面的所有的类我都有办法去操作,哪怕它不是对外接口
。
- Maven 的层次更高 ,是一种业务范畴/功能模块性质的划分
- 模块化 更加底层 ,可以看成是对一个个接口的划分
精进一下 : 结合 Maven 和 模块化 ,实现 Maven级别的高效 API 控制
其实也简单 ,就是让引入 Maven 包之后 ,只能使用我 export 出来的类:
module test.a {
exports com.test.api;
// 屏蔽后 , 再调用时会报错
// exports com.test.inner;
}
module test.main {
requires test.a;
}
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>21</source>
<target>21</target>
<release>21</release>
</configuration>
</plugin>
</plugins>
</build>
// 执行的时候就会有一次,说对应的 package 没有 export
Exception in thread "main" java.lang.IllegalAccessError: class com.main.MainTestService (in module test.main) cannot access class com.test.inner.TestInnerService (in module test.a) because module test.a does not export com.test.inner to module test.main
at test.main/com.main.MainTestService.main(MainTestService.java:12)
- 也不知道用的对不对 ,反正效果出来了,用法也简单
- Module-A 中有两个类 ,一个是 API 接口 ,一个是内部类
- 如果不使用 module-info.java 时 ,只引用 dependency ,两个类都可以使用
- 引入 module-info.java
并且控制 export 后,inner 类再调用就报错了
总结
出于对于这个特性的不了解 ,性质来了多想了一点,东西不多,内容不复杂,纯唠嗑。
好像确实有应用场景啊,还挺好玩。
最后的最后 ❤️❤️❤️👇👇👇
- 👈 欢迎关注 ,超200篇优质文章,未来持续高质量输出 🎉🎉
- 🔥🔥🔥 系列文章集合,高并发,源码应有尽有 👍👍
- 走过路过不要错过 ,知识无价还不收钱 ❗❗