标签:结构 依赖性 数据类型 java编程 .com 功能 开发 创建 访问
如何使用模块--从编写源代码到编译,打包和运行程序。
使用如下目录层次结构来编写,编译,打包和运行源代码:
src目录用于保存源代码,其中包含一个com.jdk9.m的子目录,并且创建一个同名的com.jdk9.m模块名,并将其源代码保存在整个子目录下。注:这个子目录不一定要与模块名相同。
mods目录将已编译的代码保存在展开的目录层次结构中。如果需要,可以使用此目录中的代码运行应用程序。
lib存储打包成一个模块化的JAR,可以使用模块化JAR来运行程序,也可以将模块JAR提供给可以运行程序的其他开发人员。
创建一个名为module-info.java的文件,在文件中声明模块的代码:
module com.jdk9.m { }
JDK9中的每个Java类型都是模块的成员,甚至是int,long和char等原始类型。所有原始类型都是java.base模块的成员。JDK9中的Class类有一个名为getModule()的新方法,它返回该类作为其成员的模块引用。
注:所有原始数据类型都是java.base模块的成员,可以使用int.class.getModule()获取int基本类型的模块的引用。
Welcome类的源代码如下:
package com.jdk9.m public class Welcome { public static void main(String[] args) { Class<Welcome> cls = Welcome.class; Module mod = cls.getModule(); String modName = mod.getName(); System.out.println("Module Name: " + modName); } }
最终的目录结构如下:
使用javac命令编译远点并将编译的代码保存在mods目录下。
> javac -d mods --module-source-path src src\com.jdk.m\module-info.java src\com.jdk.m\Welcome.java
-d mods将所有编译的类文件保存到mods目录下。
--modules-source-path src指定src目录的子目录包含多个模块的源代码,其中每个子目录名称与包含源代码的子目录的模块名称相同。
可以使用javac的--module-version选项,可以指定正在编译的模块的版本,模块版本保存在module-info.class文件中。
JDK9最重要和最令人激动的功能之一是模块系统,该模块系统是以代码名称Jigsaw的项目开发的。
在JDK9之前,开发一个Java应用程序通常包括以下步骤:
20多年来,Java社区以这种编写,编译,打包和部署Java代码的方式开发。这样部署和运行Java代码存在如下问题:
这些问题在Java社区中非常频繁,得到一个名字--JAR-Hell。
Java9通过引入开发,打包和部署Java应用程序的新方法来解决这些问题,在Java9中,Java应用程序由称为模块的小型交互组件组成,Java9已经将JDK/JRE组织为一组模块。
Java9引入了一个称为模块的新的程序组件,可以将Java程序视为具有明确定义的边界和这些模块之间依赖关系的交互模块的集合。模块系统的开发具有以下目标:
(1)可靠的配置
(2)强封装
(3)模块化JDK/JRE
可靠的配置解决了用于查找类型的容易出错的类路径机制的问题,模块必须声明对其他模块的显示依赖。模块系统验证应用程序开发的所有阶段的依赖关系--编译时,链接时和运行时。假设一个模块声明对另一模块的依赖,并且第二个模块在启动时丢失,JVM检测到依赖关系丢失,并在启动时失败,在Java9之前,当使用缺少的类型时,这样的应用程序会生成运行时错误(不是启动时)。
强大的封装解决了类路径上跨JAR的公共类型的可访问性问题。模块必须明确声明其中哪些公共类型可以被其他模块访问。
模块是代码和数据集合,它可以包含Java代码和本地代码。
对于Java代码,模块可以看做零个或多个包的集合。除了其名称,模块定义包括以下内容:
JDK9之前,一个包中的public类型可以被前台包访问,没有任何限制。也就是说,包没有控制它们包含的类型的可访问性。JDK9中的模块系统对类型的可访问性提供了细粒度的控制。
模块之间的可访问性是所使用的模块和使用模块之间的双向协议:模块明确地使其公共类型可供其他模块使用,而且使用这些公共类型的模块明确声明对第一个模块的依赖,模块中所有未导出的软件包都是模块的私有的,他们不能再模块之外使用。
将包中的API设置为公共供其他模块使用被称之为导出包。
模块系统只知道一个模块:java.base,java.base模块不依赖与任何其他模块,所有其他模块都隐含地依赖于java.base模块。
构建模块图旨在编译时,链接时和运行时解析模块依赖关系,模块解析从根模块开始,并遵循依赖关系链接,直到达到java.base模块。
可以创建一个不包含任何代码的模块,它收集并重新导出其他模块的内容,这样的模块称为聚合模块。假设有一个模块依赖于五个模块,可以为这五个模块创建一个聚合模块,现在你的模块只要依赖于一个模块--聚合模块。
本节包含用于声明模块的语法的快速概述。使用模块声明来定义模块,是Java编程语言中的新概念:
[open] module <moduleName> {
<module-statement>;
......
}
open修饰符是可选的,它声明一个开放的模块,一个开放的模块导出所有的包,以便其他模块使用反射访问。<moduleName>是要定义的模块的名称,<module-statement>是一个模块语句。模块声明中可以包含零个或多个模块语句:
模块名称可以是Java限定标识符,与包命名约定类型,使用反向域名模式为模块提供唯一的名称。
JDK9中,open,module,requires,transitive,exports,opens,to,uses,provices,with是受限关键字,只有在具体位置出现在模块声明中时,它们才具有特殊意义。可以将它们用作程序中其他地方的标识符。
导出语句将模块的指定包导出到所有模块或编译时和运行时的命令模块列表。形式如下:
exports <package>;
exports <package> to <module1>, <module2>;
实例:
module com.jdk9.module {
exports com.jdk9.module.core;
exports com.jdk9.module.util to com.jdk9.module.internal, com.jdk9.module.server;
}
开放语句允许对所有模块的反射访问指定的包或运行时指定的模块列表。其他模块可以反射访问指定包中的所有类型以及这些类型的所有成员(私有和公共),开放语句采用如下形式:
opens <package>;
opens <package> to <module1>, <module2>;
需要(require)语句声明当前模块对另一个模块的依赖关系,
requires <module>;
requires transitive <module>;
requires static <module>;
requires transitive static <module>;
static标示在编译时的依赖是强制的,但在运行时是可选的:requires static N意味着模块M需要模块N,模块N必须在编译时出现才能编译模块M,而在运行时存在模块N是可选的。
transitive当前模块依赖其他模块具有隐式依赖性,假设有三个模块P,Q和R,假设模块Q包含requires transitive R语句,如果模块P包含requires Q,这意味着模块P隐含依赖模块R。
Java允许使用服务提供者和服务使用者分离的服务提供者机制。JDK9运行使用语句uses和provides实现其服务。
use语句可以指定服务接口的名字,当前模块就会发现它,使用java.util.ServiceLoader类进行加载:
uses <service-interface>
实例:
module M {
uses com.jdk9.prime.PrimeChecker;
}
com.jdk9.prime.PrimeChecker是一个服务接口,其实现类将由其他模块提供,模块M将使用java.util.ServiceLoader类来发现和加载此接口的实现。
provide语句指定服务接口的一个或多个服务厅程序实现类:
provide <service-interface> with <service-impl-class1>, <service-impl-class2>;
实例:
module P {
uses com.jdk9.CsvParser;
provides com.jdk9.CsvParser with com.jdk9.CsvParserImpl;
provides com.jdk9.prime.PrimeChecker with com.jdk9.prime.PrimeCheckerImpl;
}
模块声明存储在名为module-info.java的文件中,该文件存储在该模块的源文件层次结构的根目录下。
Java编译器将模块声明编译为名为module-info.class的文件。module-info.class文件被称为模块描述符。它被放置在模块的编译代码层次结构的根目录下。如果将模块的编译代码打包到jar文件中,则module-info.class文件将存储在jar文件的根目录下。
在模块系统的初始原型中,模块声明还包括模块版本。包括模块版本在声明中使模块系统的实现复杂化,所以模块版本从声明中删除。模块描述符(类文件格式)的可扩展格式被利用来向模块添加版本。当将模块的编译代码打包到jar中时,该jar工具提供了一个添加模块版本的选项,最后将其添加到module-info.class文件中。
模块的artifact可以存储在:
当模块的编译代码存储在目录中时,目录的根目录包含模块描述符(module-info.class文件),子目录是包层次结构的镜像。
当JAR包含模块的编译代码时,JAR称为模块化JAR。模块化JAR在根目录下包含一个module-info.class文件。
无论在JDk9之前使用JAR,现在都可以使用模块化JAR。例如,模块化JAR可以放置在类路径上,在这种情况下,模块化JAR中的module-info.class文件将被忽略,因为module-info中不是有效的类名。
JDK9引入了一种称为JMOD的新格式来封装模块。JMOD文件使用.jmod扩展名。JDK模块被编译成JMOD格式,放在JDK_HOMEjmods目录中。例如,可以找到一个包含java.base模块内容的java.base.jmod文件。仅在编译时和链接时才支持JMOD文件。它们在运行时不受支持。
标签:结构 依赖性 数据类型 java编程 .com 功能 开发 创建 访问
原文地址:http://www.cnblogs.com/lujiango/p/7852120.html