Java 9 模块化(Modularity)

本文详细介绍了Java 9的模块化特性,包括Java Platform Module System (JPMS)、Project Jigsaw以及模块化带来的强封装、可靠配置和类路径问题的解决。通过实例展示了如何创建、编译和执行Java模块,强调了模块的可读性、可访问性和服务注册。同时,探讨了模块解析过程、使用jlink构建自定义运行时镜像和构建模块化JAR文件的方法。最后,提到了开发工具的支持情况和模块化的未来发展。
摘要由CSDN通过智能技术生成

JDK9的发布一直在推迟,终于在2017年9月21日发布了。下面是JDK9的几个下载地址:
JDK9.0.1 Windows-x64下载地址
Oracle Java 官网下载地址
OpenJDK 9官网
OpenJDK JDK9下载

从安装的JDK9文件夹下会发现没有jre文件夹了,并且多了一个jmods文件夹,想想为什么?
传统的jar文件是在运行时runtime使用,而 .jmods文件是在开发时development time使用。

这一次,Java9带来的模块化(Modularity)是一次重大的改变。对于在此之前(Java8及以前)的Java发布版本所添加的新特性,你都可以随意使用,但是Java9不同,这次Java9的平台模块化系统(Java Platform Modular System)在思考、设计、编写Java应用程序方面都是一个全新的改变。

1.Java 9 模块化简介

模块化是Java9发布版本最重要最强大的改变,此外Java9还带来了许多新的改变,例如支持HTTP2.0、交互式Shell(叫做jshell)等。那么模块化究竟会带来什么好处呢?为何要引入模块化?
模块(module)可以是任意东西,从一组代码实体、组件或UI类型到框架元素再到完整的可重用的库。
模块化在软件开发中通常要到达两个目标:

 - 分而治之(Divide and conquer approach):对于非常大的问题通常需要将大问题分解成一个个的小问题,然后单独解决它们。
 - 实现具有封装性和明确定义的接口:模块化后就可以隐藏模块的内部实现(称为封装encapsulation),同时暴露给用户的东西称为接口(interface)。

现在回顾下封装:
private 修饰成员变量和方法,封装的边界是Class(类)
protected 修饰成员变量和方法,封装的边界是Package(包)
无修饰符 修饰成员变量和方法或类型(Types),封装的边界是Package(包)
对于封装,难道有这些还不够吗?上面这些修饰符都集中在控制访问成员变量和方法上面。而对于类型(types)的访问保护(封装)只能让它在包层级保护package-protected。模块化可以在更大的粒度上进行封装,对类型的保护变成private。
来看几个没有模块化带来的问题的案例:

1.1 无法隐藏内部API和类型

为了更好的重用一个字符串排序的工具类,将它打包成一个jar文件,它又两个包组成:acme.util.stringsorter和acme.util.stringsorter.internal。
前者包含只有一个方法sortStrings(List)的类StringSorterUtil,后者包含只有一个方法sortStrings(List)的BubbleSortUtil类,BubbleSortUtil类用的是著名的Bubble排序算法对给定的字符串排序,调用StringSorterUtil的sortStrings方法实际上是反向代理执行BubbleSortUtil类的sortStrings方法。
这里写图片描述
后来jar包开发者发现哈希Hash排序算法更优于Bubble排序算法,于是升级了下,将HashSortUtil类加到了acme.util.stringsorter.internal包下面并移除掉了原来的BubbleSortUtil类。幸好单独有这么个internal包,用户调用StringSorterUtil的sortStrings方法的方式没有改变,那用户就可以直接升级这个jar包了。一切是多么的美好。
但是!还是出问题了。
jar包作者本意是acme.util.stringsorter.internal包不让用户使用,是private的,但是当用户将这个jar包加到classpath后,仍然可以直接使用BubbleSortUtil类,这并不是jar包开发者所希望的。现在升级了版本后,那些直接使用BubbleSortUtil类的应用由于找不到BubbleSortUtil类连编译都通不过。显然,即使将包命名为internal还是无法避免用户去访问它。
Java平台内部API是不建议使用的,尽管官方给出了提醒,但还是无法避免开发者使用,现在在Java9中已经将其隐藏了,例如以sun开头的包。
那么有没有什么方式来封装这些internal类呢?模块!

1.2 可靠性问题

应用启动运行了几个小时候没有发生错误,但是,并不能说之后就没有问题。比如或许有一个类还没有被执行到,当执行到它时,JVM发现找不到这个类的一个import,抛出类找不到异常。又或许同一个类的多个版本加到了类路径而JVM只选择了它找到的第一个副本。难道没有一个更好的方式来确保任意的Java应用不需要执行就将会可靠reliably地运行?模块描述符!

1.3 类路径classpath问题

Jar文件仅仅是将一组类方便的放在一起而已。一旦加入到classpath中,JVM就对Jar中的所有classes一视同仁放到同一个根root目录下,而不管这些class文件位置在哪。想象一个应用的成千上万的类放置在同一个目录下而没有结构的样子,这对于管理和维护将是一场噩梦。代码库越大,问题越大。例如有20悠久历史的Java平台本身!!!
Java 1996年发布的第一个版本至少有500个public类,到2014年发布的JDK8已经达到4200多个public类和20000多个文件。传统地,每一个JRE在运行时都要从一个库加载所有的类,这个库就是rt.jar,rt的意思是Run Time.
Java9之前,每一个runtime自带开箱即用的所有编译好的平台类,这些类被一起打包到一个JRE文件叫做rt.jar。你只需将你的应用的类放到classpath中,这样runtime就可以找到,而其它的平台类它就简单粗暴的从rt.jar文件中去找。尽管你的应用只用到了这个庞大的rt.jar的一部分,这对JVM管理来说不仅增加了非必要类的体积,还增加了性能负载。
Java8的rt.jar大概 60 MB大小,目前尚可忍受,但如果一直这样下去想象之后它的体积肯定会越来越庞大,难道没有更好的方式来运行java吗?Java9模块化可以按需自定义runtime!这也就是jdk9文件夹下没有了jre目录的原因!

1.4 Java Platform Module System(JPMS)

JPMS(JAVA平台模块化系统)引入了一个新的语言结构来构建可重用的组件,称为模块modules。在Java9 的模块中,你可以将某些类型types和包packages组合到一个模块module中,并给模块提供如下3个信息:

  • 名称:模块的唯一的名字,例如 com.acme.analytics,类似于包名。
  • 输入:什么是模块需要和使用到的?什么是模块编译和运行所必需的?
  • 输出:什么是模块要输出或暴露给其他模块的?

默认地,一个模块中的每一个java类型只能被该模块中的其他类型所访问。要想暴露类型给外部的模块使用,需要明确指定哪些包packages要暴露export。任何模块只能在包的层级上暴露,一旦暴露了某个包,那这个包中的所有的类型就都可以被外部模块访问。如果一个Java类型所在的包没有暴露,那么外部其他模块是无法import它的,即使这个类型是public的。

JPMS具有两个重要的目标,要牢记:

  • 强封装Strong encapsulation:由于每一个模块都声明了哪些包是公开的哪些包是内部的,java编译和运行时就可以实施这些规则来确保外部模块无法使用内部类型。
  • 可靠配置Reliable configuration:由于每一模块都声明了哪些是它所需的,那么在运行时就可以检查它所需的所有模块在应用启动运行前是否都有。

    除了上面两个核心的目标,JPMS还有另外一个重要的目标是易于扩展和使用即使在庞大的类库上。
    所以对Java平台自身进行了模块化,实施于项目Project Jigsaw

1.5 Project Jigsaw

Modular development starts with a modular platform. —Alan Bateman 2016.9
模块化开发始于模块化的平台。
要写模块化代码,需要将Java平台模块化。Java9之前,JDK中所有的类都糅杂在一起,像一碗意大利面。这使得JDK代码库很难改变和发展。
Java 9 模块化JDK如下图:
这里写图片描述
Project Jigsaw 有如下几个目标:

  • 可伸缩平台Scalable platform:逐渐从一个庞大的运行时平台到有有能力缩小到更小的计算机设备。
  • 安全性和可维护性Security and maintainability:更好的组织了平台代码使得更好维护。隐藏内部APIs和更明确的接口定义提升了平台的安全性。
  • 提升应用程序性能Improved application performance:只有必须的运行时runtimes的更小的平台可以带来更快的性能。
  • 更简单的开发体验Easier developer experience:模块系统与模块平台的结合使得开发者更容易构建应用和库。

模块化的另外一个重要的方面是版本控制versioning。现在的JPMS不支持versioning!!!

在控制台输入如下命令可以查看所有的模块:java –list-modules
这里写图片描述

查看某个模块(例如java.sql)的详情(描述符)使用–describe-module或-d:
java –describe-module java.sql

$ java -d java.sql
java.sql@9
exports java.sql
exports javax.sql
exports javax.transaction.xa
requires java.base mandated
requires java.logging transitive
requires java.xml transitive
uses java.sql.Driver

从Java平台的模块描述符中可以看出有几个关键词requires(输入)、exports(输出)、users(使用服务:消费者)、providers(提供服务:服务实现者)、transtive(传递性)
java.se 是Java SE包含的所有模块:
这里写图片描述

java.base是最基础的模块,也是java开发所需要的最小的模块,没有它就写不了java代码。因此该模块会自动隐含地加入所有模块(即所有模块描述符会隐含这条语句requires java.base)&#x

  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值