Java|Java9新特性中的模块化到底是什么( 二 )


注意:exports和opens的区别在于 , exports导出的包可以在编译和runtime期间访问其public成员 。 opens声明的包 , 则还可以在运行期间通过反射来访问其public和private成员 。
为什么要用模块化
那么 , 为什么要用模块化呢 , 使用模块化有什么好处呢?看起来代码的编写反而更为复杂了!
显式管理依赖:
每个模块需要显式声明自己需暴露的包 , 而自己所依赖的和自己内部使用的包 , 则不会暴露 , 也不会被外部引用到 。 这种机制彻底的杜绝了Java9以前Jar包依赖买一送一堆的场景 , 大大的减少Jar包冲突的情况 。
场景:比如我的项目中本身已经依赖了hibernate-validator用来做参数校验 , 在后续的开发中由于加解密需要又引入了一个提供了加解密api的第三方的jar , 这个第三方jar也依赖了另外一个版本hibernate-validator , 那么在项目中就存在了两个不同版本的hibernate-validator , 这个时候就会出现jar包冲突 。 这个时候模块化就可以完美解决这个问题 , 这个第三方加解密的jar可以在module-info.java中只exports出本身加解密功能的部分package , 而不会exports出这个jar本身所依赖的其他jar包 。
强封装性:
模块显式的选择向其他模块只暴露需要的类或接口 , 而完美的隐藏了内部实现的细节及其他内部成员 , 实现了真正的封装 。
场景:比如下图module-common中的枚举类DefaultResponseEnum , 定义了系统内置的几种默认响应码 , 因为被定义在了inner包中 , 而inner包又没有被声明exports , 所以这个枚举类只能在module-common内部使用 , 避免了被其他模块直接使用 。

安全性:
显式依赖管理及强封装性 , 大大的减少了程序运行时不必要模块的加载 , 减少了Java运行期间的被攻击面 。 代码真正意义上可以按照作者的设计思路进行公开和隐藏 , 限制了反射的滥用 , 更好的保护了那些不建议被外部直接使用或过时的内部类 。
规范性:
显示的声明暴露的内容 , 可以让第三方库的开发者更好的管理自己的内部实现逻辑和内部类 。 第三方库作者可以更轻松的管理自己的内部类的访问权限和反射调用权限 , 避免了出现sun.misc.BASE64Encoder这些内部类在已经被官方声明了过时和不建议使用的前提下 , 仍有大量的开发者去随意使用的情况 。 因为在Java9之前 , JDK开发者只能建议 , 而无法实现强制约束 。
场景:比如我们提倡的面向接口编程 , 要求在controller中只能注入service层的接口 , 而不能直接注入其实现类 , 但是这个要求只是个规范 , 无法强制约束 , Java9以前 , 我们仍然可以在直接注入service层的实现类 , 代码仍然可以照常运行 , 只是没那么规范而已 。 但是在Java9以后 , 我们可以在service的模块中只exports出接口 , 这样controller就无法直接注入实现类 , 在编译期就会报错 , 实现了强约束 。
自定义最小运行时映像:
Java因为其向后兼容的原则 , 不会轻易对其内容进行删除 , 包含的陈旧过时的技术也越来越多 , 导致JDK变得越来越臃肿 。 而Java9的显示依赖管理使得加载最小所需模块成为了可能 , 我们可以选择只加载必须的JDK模块 , 抛弃如java.awt javax.swing java.applet等这些用不到的模块 。 这种机制 , 大大的减少了运行Java环境所需要的内存资源 , 在对于嵌入式系统开发或其他硬件资源受限的场景下的开发非常有用 。
孵化器模块的支持:
Java9中 , 引入了孵化器模块 , 使用了固定的前缀jdk. incubator 。 孵化器模块是一种提供实验API的机制 , 相当于是beta版 , 其中的内容在后续的版本中可能会被改动或删除 。 这个机制的存在 , 可以让开发者在明确的知道其不稳定性的同时 , 如果感兴趣的话 , 可以尝试提前接触和使用这些实验性的功能 , 使得这个新功能可以在真实环境中不断打磨完善 。
场景:如Java9中提供的jdk. incubator.httpclient模块 , 提供了一个全新的HttpClient API , 并且在Java11中孵化为正式模式 java.net.http , 提供了高性能的异步非阻塞调用支持 。
【Java|Java9新特性中的模块化到底是什么】本文为个人学习整理 , 如有描述错误或者对相关内容感兴趣 , 欢迎评论或私信交流 , 一起讨论、共同进步 。