码迷,mamicode.com
首页 > 其他好文 > 详细

JDK9-模块化系统

时间:2017-11-27 23:40:14      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:结构   依赖性   数据类型   java编程   .com   功能   开发   创建   访问   

0. 实例

如何使用模块--从编写源代码到编译,打包和运行程序。

0.1 使用命令行编写和运行模块程序

0.1.1 设置目录

使用如下目录层次结构来编写,编译,打包和运行源代码:

技术分享图片

src目录用于保存源代码,其中包含一个com.jdk9.m的子目录,并且创建一个同名的com.jdk9.m模块名,并将其源代码保存在整个子目录下。注:这个子目录不一定要与模块名相同。

mods目录将已编译的代码保存在展开的目录层次结构中。如果需要,可以使用此目录中的代码运行应用程序。

lib存储打包成一个模块化的JAR,可以使用模块化JAR来运行程序,也可以将模块JAR提供给可以运行程序的其他开发人员。

0.1.2 编写源代码

创建一个名为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);
	}
}

最终的目录结构如下:

技术分享图片

0.1.3 编译

使用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文件中。 

技术分享图片

 

 

 

 

0.2 使用eclipse编写和运行模块程序

1. 背景

JDK9最重要和最令人激动的功能之一是模块系统,该模块系统是以代码名称Jigsaw的项目开发的。

在JDK9之前,开发一个Java应用程序通常包括以下步骤:

  • Java源代码以Java类型(类,接口,枚举和注释)的形式编写。
  • 不同的Java类型被安排在一个包中,而且始终属于一个明确或默认的包。
  • 编译的代码被打包成一个或多个jar文件,也称为应用程序jar。因为它们包含应用程序代码,一个程序包张的代码可能会引用多个jar。
  • 应用程序可能使用类库,类库作为一个或多个jar文件提供给应用程序使用。
  • 通过将所有jar文件,应用程序jar文件来jar类库放在类路径上来部署应用程序。

20多年来,Java社区以这种编写,编译,打包和部署Java代码的方式开发。这样部署和运行Java代码存在如下问题:

  • 一个包只是一个类型等待容器,而不强制执行任何可访问性边界:包中的公共类型可以在所有其他包中访问;没有办法阻止在一个包中公开类型的全局可见性。
  • 除了以java和javax开头的包外,包颖是开放扩展的。如果你在具有包级别访问的jar中进行类型化,则可以在其他jar中访问定义与你的名称相同的包中的类型。
  • Java运行时会看到从jar列表加载的一组包。没有办法知道是否在不同的jar中有多个相同类型的副本。Java运行时首先加载的类路径中遇到的jar中找到的类型。
  • Java运行时可能会出现由于应用程序在类路径中需要的其中一个jar引起的运行时缺少类型的情况,当代码尝试使用它们时,缺少的类型会引起运行时错误。
  • 在启动时没有办法知道应用程序中使用的某些类型已经丢失。还可以包含错误的jar文件版本,并在运行时产生错误。

这些问题在Java社区中非常频繁,得到一个名字--JAR-Hell。

Java9通过引入开发,打包和部署Java应用程序的新方法来解决这些问题,在Java9中,Java应用程序由称为模块的小型交互组件组成,Java9已经将JDK/JRE组织为一组模块。

2. 全新的模块系统

Java9引入了一个称为模块的新的程序组件,可以将Java程序视为具有明确定义的边界和这些模块之间依赖关系的交互模块的集合。模块系统的开发具有以下目标:

(1)可靠的配置

(2)强封装

(3)模块化JDK/JRE

可靠的配置解决了用于查找类型的容易出错的类路径机制的问题,模块必须声明对其他模块的显示依赖。模块系统验证应用程序开发的所有阶段的依赖关系--编译时,链接时和运行时。假设一个模块声明对另一模块的依赖,并且第二个模块在启动时丢失,JVM检测到依赖关系丢失,并在启动时失败,在Java9之前,当使用缺少的类型时,这样的应用程序会生成运行时错误(不是启动时)。

强大的封装解决了类路径上跨JAR的公共类型的可访问性问题。模块必须明确声明其中哪些公共类型可以被其他模块访问。

3. 什么是模块化

模块是代码和数据集合,它可以包含Java代码和本地代码。

对于Java代码,模块可以看做零个或多个包的集合。除了其名称,模块定义包括以下内容:

  • requires其他模块(或依赖于)的列表
  • exports包列表(其public API),其他模块可以使用
  • open的包(整个API,共有和私有),其他模块可以反射调用
  • 使用的服务列表
  • 提供的服务的实现列表

4. 模块依赖关系

JDK9之前,一个包中的public类型可以被前台包访问,没有任何限制。也就是说,包没有控制它们包含的类型的可访问性。JDK9中的模块系统对类型的可访问性提供了细粒度的控制。

模块之间的可访问性是所使用的模块和使用模块之间的双向协议:模块明确地使其公共类型可供其他模块使用,而且使用这些公共类型的模块明确声明对第一个模块的依赖,模块中所有未导出的软件包都是模块的私有的,他们不能再模块之外使用。

将包中的API设置为公共供其他模块使用被称之为导出包。

模块系统只知道一个模块:java.base,java.base模块不依赖与任何其他模块,所有其他模块都隐含地依赖于java.base模块。

构建模块图旨在编译时,链接时和运行时解析模块依赖关系,模块解析从根模块开始,并遵循依赖关系链接,直到达到java.base模块。

5. 聚合模块

可以创建一个不包含任何代码的模块,它收集并重新导出其他模块的内容,这样的模块称为聚合模块。假设有一个模块依赖于五个模块,可以为这五个模块创建一个聚合模块,现在你的模块只要依赖于一个模块--聚合模块。

6. 声明模块

本节包含用于声明模块的语法的快速概述。使用模块声明来定义模块,是Java编程语言中的新概念:

[open] module <moduleName> {

  <module-statement>;

  ......

}

open修饰符是可选的,它声明一个开放的模块,一个开放的模块导出所有的包,以便其他模块使用反射访问。<moduleName>是要定义的模块的名称,<module-statement>是一个模块语句。模块声明中可以包含零个或多个模块语句:

  • 导出语句(exports),导出模块,其他模块访问。
  • 开放语句(opens),开放当前模块,其他模块可以访问,包括反射调用等。
  • 需要语句(requires),声明模块对另一个模块的依赖关系。
  • 使用语句(uses),表达服务消费。
  • 提供语句(provides),表达服务提供。

6.1 模块命名

模块名称可以是Java限定标识符,与包命名约定类型,使用反向域名模式为模块提供唯一的名称。

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

6.2 模块的访问控制

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

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>;

6.3 声明依赖关系

需要(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。

6.4 配置服务

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;

}

7. 模块描述符

 7.1 编译模块声明

模块声明存储在名为module-info.java的文件中,该文件存储在该模块的源文件层次结构的根目录下。

Java编译器将模块声明编译为名为module-info.class的文件。module-info.class文件被称为模块描述符。它被放置在模块的编译代码层次结构的根目录下。如果将模块的编译代码打包到jar文件中,则module-info.class文件将存储在jar文件的根目录下。

7.2 模块版本

在模块系统的初始原型中,模块声明还包括模块版本。包括模块版本在声明中使模块系统的实现复杂化,所以模块版本从声明中删除。模块描述符(类文件格式)的可扩展格式被利用来向模块添加版本。当将模块的编译代码打包到jar中时,该jar工具提供了一个添加模块版本的选项,最后将其添加到module-info.class文件中。

 8. 打包模块

模块的artifact可以存储在:

  • 目录中
  • 模块化的JAR文件中
  • JMOD文件中,它是JDK9中引入的一种新的模块封装格式

8.1 目录中的模块

当模块的编译代码存储在目录中时,目录的根目录包含模块描述符(module-info.class文件),子目录是包层次结构的镜像。

8.2 模块化JAR中的模块

当JAR包含模块的编译代码时,JAR称为模块化JAR。模块化JAR在根目录下包含一个module-info.class文件。

无论在JDk9之前使用JAR,现在都可以使用模块化JAR。例如,模块化JAR可以放置在类路径上,在这种情况下,模块化JAR中的module-info.class文件将被忽略,因为module-info中不是有效的类名。

8.3 JMOD文件中的模块

JDK9引入了一种称为JMOD的新格式来封装模块。JMOD文件使用.jmod扩展名。JDK模块被编译成JMOD格式,放在JDK_HOMEjmods目录中。例如,可以找到一个包含java.base模块内容的java.base.jmod文件。仅在编译时和链接时才支持JMOD文件。它们在运行时不受支持。

 

JDK9-模块化系统

标签:结构   依赖性   数据类型   java编程   .com   功能   开发   创建   访问   

原文地址:http://www.cnblogs.com/lujiango/p/7852120.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!