Java 9中最重要的功能,毫无疑问就是模块化(Module),它将自己长期依赖JRE的结构,转变成以Module为基础的组件,当然这在使用Java 9 开发也和以前有着很大的不同。

Java8或更加早期的系统的问题

  1. Jar文件,像rt.jar等jar文件太大的以至于不能使用在小设备和应用中。
  2. 因为JDK是太大的,我们的应用或设备不能支持更好的平台.
  3. 由于修饰符是public的缘故,每个人都可以通过此来进行访问,所以在当前Java系统的封闭性不是很强。
  4. 由于JDK,Jre过于庞大,以至于很难进行测试和维护应用。
  5. 由于public的关系,Java比较开放。不可避免的能访问象sun., .internal.*等的一些内部不重要的APIs。

Java9模块系统的特性

  1. 在Java SE 9中分离了JDK, JRE,jar等为更小的模。因此我们可以方便的使用任何我们想要的模块。因此缩减Java应用程序到小设备是非常容易的。
  2. 更加容易的测试和维护。
  3. 支持更好的平台。
  4. public不再仅仅是public。现在已经支持非常强的封闭性(不用担心,后边我们会用几个例子来解释)。
  5. 我们不能再访问内部非关键性APIs了。
  6. 模块可以非常安全地帮助我们掩藏那些我们不想暴露的内部细节,我们可以得到更好的Security。
  7. 应用会变的非常小,因为我们可以只使用我们要用的模块。
  8. 组件间的松耦合变得非常容易。
  9. 更容易支持唯一责任原则(SRP)。

目录结构

以前的jre中有一个很大的架包,jdk8 中rt.jar有62M,即便运行一个最简单的HelloWorld,都必须带上它。

jdk9 的目录

我们发现,jdk9 中没有Jre 文件,也没有rt.jar等这种很大的架包,但是它有了一个新的文件jmods,模块都是放在jmods文件夹中。

目前共有98个模块。

Module的相关属性

在主目录的/main/java/下新建module-info.java文件,可以管理这个项目的module。

module M {

}

模块命名

又称模块描述文件

模块命名需要保证单一,可以使用反向域名模式,如com.wuwii.xxx.xxx,这个模块会导出包com.wuwii

在JDK 9中, open, module, requires, transitive, exports, opens, to, uses, provides 和 with是受限关键字。只有当具体位置出现在模块声明中时,它们才具有特殊意义。 可以将它们用作程序中其他地方的标识符。

例如:可以在程序中声明一个module变量。

访问权限

模块之间的关系被称作readability(可读性),代表一个模块是否可以找到这个模块文件,并且读入系统中(注意:并非代表可以访问其中的类型)。在实际的代码,一个类型对于另外一个类型的调用,我们称之为可访问性(Accessible),这意味着可以使用这个类型; 可访问性的前提是可读性,换句话说,现有模块可读,然后再进一步检测可访问性(安全)。

导出语句将模块的指定包导出到所有模块或编译时和运行时的命名模块列表。 它的两种形式如下:

exports <package>;
exports <package> to <module1>, <module2>...;

以下是使用了导出语句的模块示例:

module java.xml.ws {
……
exports com.oracle.webservices.internal.api.databinding to
jdk.xml.ws;
exports com.sun.xml.internal.ws.addressing to
jdk.xml.ws,
java.xml.bind;
……
}

开放语句允许对所有模块的反射访问指定的包或运行时指定的模块列表。 其他模块可以使用反射访问指定包中的所有类型以及这些类型的所有成员(私有和公共)。 开放语句采用以下形式:

opens <package>;
opens <package> to <module1>, <module2>...;

Tips

对比导出和打开语句。 导出语句允许仅在编译时和运行时访问指定包的公共API,而打开语句允许在运行时使用反射访问指定包中的所有类型的公共和私有成员。

module N {
exports M;
opens M;
}

阅读有关模块的时候会遇到三个短语:

  • 模块M导出包P
  • 模块M打开包Q
  • 模块M包含包R

前两个短语对应于模块中导出语句和开放语句。 第三个短语意味着该模块包含的包R既不导出也不开放。 在模块系统的早期设计中,第三种情况被称为“模块M隐藏包R”。

声明依赖关系

需要(require)语句声明当前模块与另一个模块的依赖关系。 一个名为M的模块中的“需要N”语句表示模块M取决于(或读取)模块N。语句有以下形式:

requires <module>;
requires transitive <module>;
requires static <module>;
requires transitive static <module>;
  • require语句中的静态修饰符表示在编译时的依赖是强制的,但在运行时是可选的。
  • requires static N语句意味着模块M取决于模块N,模块N必须在编译时出现才能编译模块M,而在运行时存在模块N是可选的。
  • require语句中的transitive修饰符会导致依赖于当前模块的其他模块具有隐式依赖性。
  • 假设有三个模块P,Q和R,假设模块Q包含requires transitive R语句,如果如果模块P包含包含requires Q语句,这意味着模块P隐含地取决于模块R。

配置服务

Java允许使用服务提供者和服务使用者分离的服务提供者机制。 JDK 9允许使用语句(uses statement)和提供语句(provides statement)实现其服务。

使用语句可以指定服务接口的名字,当前模块就会发现它,使用 java.util.ServiceLoader类进行加载。格式如下:

uses <service-interface>;

使用语句的实例如下:

module M {
uses com.jdojo.prime.PrimeChecker;
}

com.jdojo.PrimeChecker是一个服务接口,其实现类将由其他模块提供。 模块M将使用java.util.ServiceLoader类来发现和加载此接口的实现。

提供语句指定服务接口的一个或多个服务提供程序实现类。 它采取以下形式:

provides <service-interface>
with <service-impl-class1>, <service-impl-class2>...;

相同的模块可以提供服务实现,可以发现和加载服务。 模块还可以发现和加载一种服务,并为另一种服务提供实现。 以下是例子:

module P {
uses com.jdojo.CsvParser;
provides com.jdojo.CsvParser
with com.jdojo.CsvParserImpl;
provides com.jdojo.prime.PrimeChecker
with com.jdojo.prime.generic.FasterPrimeChecker;
}

总结

需要注意的是,不只是jdk中内置的98种模块,引用maven的第三方架包,也需要module,

如用的比较多的日志

    /**
* logger
*/
private static final Logger LOGGER = LoggerFactory.getLogger(LearnSoap.class);

配置

需要在module-info.java配置:

requires slf4j.api;

Java中的包已被用作类型的容器。 应用程序由放置在类路径上的几个JAR组成。 软件包作为类型的容器,不强制执行任何可访问性边界。 类型的可访问性内置在使用修饰符的类型声明中。 如果包中包含内部实现,则无法阻止程序的其他部分访问内部实现。 类路径机制在使用类型时线性搜索类型。 这导致在部署的JAR中缺少类型时,在运行时接收错误的另一个问题 —— 有时在部署应用程序后很长时间。 这些问题可以分为两种类型:封装和配置。

JDK 9引入了模块系统。 它提供了一种组织Java程序的方法。 它有两个主要目标:强大的封装和可靠的配置。 使用模块系统,应用程序由模块组成,这些模块被命名为代码和数据的集合。 模块通过其声明来控制模块的其他模块可以访问的部分。 访问另一个模块的部分的模块必须声明对第二个模块的依赖。 控制访问和声明依赖的是达成强封装的基础。 在应用程序启动时解决了一个模块的依赖关系。 在JDK 9中,如果一个模块依赖于另一个模块,并且运行应用程序时第二个模块丢失,则在启动时将会收到一个错误,而不是应用程序运行后的某个时间。 这是一个可靠的基础配置。

使用模块声明定义模块。 模块的源代码通常存储在名为module-info.java的文件中。 一个模块被编译成一个类文件,通常命名为module-info.class。 编译后的模块声明称为模块描述符。 模块声明不允许指定模块版本。 但诸如将模块打包到JAR中的jar工具的可以将模块版本添加到模块描述符中。

使用module关键字声明模块,后跟模块名称。 模块声明可以使用五种类型的模块语句:exports,opens,require,uses和provide。 导出语句将模块的指定包导出到所有模块或编译时和运行时的命名模块列表。 开放语句允许对所有模块的反射访问指定的包或运行时指定的模块列表, 其他模块可以使用反射访问指定包中的所有类型以及这些类型的所有成员(私有和公共)。 使用语句和提供模块语句用于配置模块以发现服务实现并提供特定服务接口的服务实现。

从JDK 9开始,open, module, requires, transitive, exports,opens,to,uses,provides和with都是受限关键字。 只有当具体位置出现在模块声明中时,它们才具有特殊意义。

参考文章

初探Java 9 的的模块化的更多相关文章

  1. (札记)Java应用架构设计-模块化模式与OSGi

    本书主要模块化模式的优点.模块化方法与模式.OSGi简单使用等内容.分3大部分: 第一部分介绍了模块化概念.为什么要模块化,以及一些模块化要考虑的东西,如模块粒度,依赖关系,重用性灵活性等. 第二部分 ...

  2. 初探Java字符串

    转载: 初探Java字符串 String印象 String是java中的无处不在的类,使用也很简单.初学java,就已经有字符串是不可变的盖棺定论,解释通常是:它是final的. 不过,String是 ...

  3. Web/Java Web项目如何模块化?没有正文,别点

    事情是这样的,两三年前做了几个Java Web项目,由于薪资原因,原主程都离开了. 由于公司不规范,也没有留下正规的开发文档,只有一个源程序在手里.后面的很多系统维护都很被动. 领导就觉得说,这样不好 ...

  4. 【转载】Java 9 新特性——模块化

    来自 <http://www.jianshu.com/p/053a5ca89bbb#> 前言 年,我们将迎来 Java 语言的 22 岁生日,22岁,对于一个人而言,正是开始大展鸿图的年纪 ...

  5. Java应用架构设计模块化模式与OSGI摘录

    在Java中,最适合模块化的单元就是Jar文件. 代码层面我们关注的太多了,熟练的开发人员现在很少争论使用模式的好处,也不再识别哪个模式适合当前需要,因为都能够本能地使用各种设计原则和模式,从GoF的 ...

  6. 初探java中this的用法

    一般this在各类语言中都表示“调用当前函数的对象”,java中也存在这种用法: public class Leaf { int i = 0; Leaf increment(){ i++; retur ...

  7. java初探/java读取文件

    import java.io.*; import java.util.Arrays; public class WriteText { public static void main(String[] ...

  8. 初探JAVA中I/O流(二)

    1.缓冲输入文件 FileReader BufferedReader FileReader可以直接对文件进行读操作.但是简化编程,加快读取速度,我们加入了缓冲机制,使用了BufferedReader. ...

  9. 初探JAVA中I/O流(一)

    一.流 流,这里是对数据交换的形象称法.进程是运行在内存中的,在运行的过程中避免不了会与外界进行数据交互.比如将数据从硬盘.控制台.管道甚至是套接字(具体点应该是我们电脑上的网卡)读到我们进程锁所占据 ...

随机推荐

  1. Python之pexpect详解

    一.引子 Pexpect程序主要用于人机对话的模拟,就是那种系统提问,人来回答yes/no,或者账号登陆输入用户名和密码等等的情况.因为这种情况特别多而且繁琐,所以很多语言都有各种自己的实现.最初的第 ...

  2. Navicat连接mysql报错1251

    Navicat无法连接MySQL8,是因为MySQL8的方式和MySQL5的加密方式不一样导致 解决方案: 1.通过命令行进入mysql数据库: C:\Windows\system32> mys ...

  3. Netty源码分析第6章(解码器)---->第2节: 固定长度解码器

    Netty源码分析第六章: 解码器 第二节: 固定长度解码器 上一小节我们了解到, 解码器需要继承ByteToMessageDecoder, 并重写decode方法, 将解析出来的对象放入集合中集合, ...

  4. linux的date命令使用指定时间的加减方法与异常

    在一般网页里,date命令减时间方法为: date -d '-100 days' 我的需求是,在指定时间上减8小时.按一般理解来看,命令写成如下样子(有异常错误的写法): date -d " ...

  5. 【RL系列】Multi-Armed Bandit笔记补充(二)

    本篇的主题是对Upper Conference Bound(UCB)策略进行一个理论上的解释补充,主要探讨UCB方法的由来与相关公式的推导. UCB是一种动作选择策略,主要用来解决epsilon-gr ...

  6. [linux] tmux终端复用神器 [转载]

    转载https://www.cnblogs.com/kevingrace/p/6496899.html Tmux是一个优秀的终端复用软件,类似GNU Screen,但来自于OpenBSD,采用BSD授 ...

  7. jaxb教程(忘记了过来看看)

    链接 原文链接

  8. 第14讲:嵌入式SQL语言(基本技巧)

    一.交互式SQL的局限 & 嵌入式SQL的必要性 专业人员(如DBA)可以熟练地运用交互式SQL语言,但普通用户却不是那么容易上手,所以需要通过数据库应用程序来使用数据库.编写一个可以与数据库 ...

  9. Task 6.2冲刺会议八 /2015-5-21

    今天把主界面大体完成了,摄像头的拼接和语音以及麦克风的功能都已经基本上实现了.但是登录界面到主界面的跳转还是没有成功.过程中遇到的问题有登录协议的地方没有明确,一直出现跳转连接异常.明天准备把跳转的部 ...

  10. Chapter 3 软件项目管理

    软件项目具有产品的不可见性.项目的高度不确定性.软件过程的多变化性.软件人员的高流动性的显著特征.有效的软件项目管理集中于人员.产品.过程和项目四个方面.软件项目的生命周期有项目启动.项目规划.项目实 ...