原文链接 译者:carvendy
JEP 220:模块化运行时镜像
作者 Mark Reinhold
创建 2014/10/23 15:05
更新 2017/05/19 01:58
类型 特性
状态 集成
域 SE
JSR 376
讨论 拼图的开发在openjdk.java.net 努力 XL
持续时间 XL
优先 l
检验人 Alan Bateman, Alex Buckley, Chris Hegarty, Mandy Chung, Paul Sandoz
发行 9
版本 8061971
块 JEP 200:模块化JDK
JEP 261:模块系统
涉及 JEP 162:模块化思想准备
JEP 282:jlink:Java连接器
JEP 201:模块化源码
概述
重构JDK和JER运行镜像到容纳这些模块和提高行为,保护和可维护性。定义新的URI方案来命名模块,类和资源存储在一个运行时镜像,而没有揭示内部结构或者镜像格式。修改存在的规范作为需要容纳的改变。
目标
- 采取一个运行时格式来存储class和资源文件:
- 更多时间和空间影响到了合法的jar格式,反过来它基于古老的zip格式 。
- 定位和加载类和资源文件到每一个模块基础;
- 可以从JDK模块和类库还有程序模块等,存储class和资源文件。
- 可以扩展容纳额外各种数据前行,例如与计算JVM数据结构和为javaclass预编译机器代码。
- 重构JDK和JRE运行时镜像在文件、开发者、发布者和最终用户之间绘制清晰的区别,并让最终用户可以信赖的。当在对比文件中的适当修改,文件内部实现和概述了改变而没有注意到。
- 提供支持方式给执行公共操作,那些今天可以被检查的内部结构运行时镜像等,例如:枚举在镜像中目前所有的class。
- 保存行为良好的应用程序的现有行为,程序将不依赖内部的JRE和JDK运行时镜像。
成功指标
模块化运行时镜像等价于JRE,JDK和紧凑的配置镜像紧接着JDK 9构建必须回归到启动、静态足迹和动态足迹基准 的代表集合。
非目标
- 保存当前运行镜像的所有方面。
- 保存所有现有API的准确当前行为。
动机
拼图项目目的是设计和实现标准模块系统Java SE 平台和允许系统对平台本身,和对于JDK。它最初的目标是更容易地实现平台 可拓展性到小驱动,提高保护和可维护性,可以提升程序执行,和提供开发者更好的工具让程序变得更大。
JEP设计在拼图项目,其中JEP 占了项目3/4的。早在JEP 200定义模块化JDK的结构和JEP 201在模块中重组了JDK源码。后续JEP将介绍实际的模块系统。
描述
当前运行时镜像结构
JDK构建系统目前有两种运行镜像:Java运行环境(JRE),它完整实现了Java SE平台;另一个就是Java开发工具(JDK),它嵌入了JRES和包括了开发工具和类库。(三个紧凑配置文件构建JRE的子集合)
JRE镜像的根目录包含两个目录,bin和lib,有以下内容:
- bin目录包含可执行二进制文件,实际运行时系统的java命令。(在Windows操作系统包含了运行时动态链接本地类库)
- lib目录包含各种文件和子目录:
JDK 镜像包含可复制的JRE在它的jre之目录和包含额外的子目录:
- bin目录包含命令行开发和调试工具例如:javac,javadoc,和jconsole,还有可复制二进制的文件在jre/bin目录下方便使用。
- 例子和样板目录分别包含示范的程序和样板代码。
- man目录包含UNIX风格的手册页;
- include目录包含C/C++头文件让使用编译本地库,接口将指向行时系统等。
- lib目录包含各种jar文件和其他类型的文件,包括JDK工件的实现,其中有tools.jar,包含编译类文件的javac编译器。
JDK镜像根目录,或JRE镜像的目录没有嵌入到JDK镜像,也包含各种COPYRIGHT, LICENSE和README文件和发行版文件,描述镜像依据简单的键值对属性,例如:
JAVA_VERSION="1.9.0"
OS_NAME="Linux"
OS_VERSION="2.6"
OS_ARCH="amd64
新运行时镜像结构
目前JRE和JDK镜像的区分是纯粹是历史原因,实现的结果让JDK1.2发行版的开发晚了和再也没有访问了。新的镜像结构将消除区别:JDK镜像将简单地称为运行时镜像,包含全集的开发工具和其他历史在JDK能找到的。
一个模块化运行时镜像将包含下列目录:
- bin目录包含任意的命令行启动器定义在模块并链接到镜像。(在Windows它将继续包含运行时系统的动态连接本地库)
- conf目录将包含.properties,.policy和其他类型文件可以让开发者、发布者和最终使用者编辑修改,那里可以发现lib目录或者其他子目录。
- lib目录在Unix下将包含运行时系统动态链接本地库,像现在如。这些可能链接到嵌入了运行时系统的程序。
- 所有其他文件和目录在lib目录中,必须被处理为运行时系统的私有实现。它们不打算拓展使用和它们的名字、格式、内容将随时可能发生变化而并不会注意。
- 全的JDK镜像将额外包含demo,sample,man,includ目录,像现在如此。
一个模块化的运行时根目录将包含重要的COPYRIGHT, LICENSE, README, and 发布 文件 。为了容易表述哪些模块目前在运行时镜像,发布文件将增强食欲新属性——MODULES,它是空间分离的列表模块的名字。这个列表将根据模块的依赖关系进行拓扑排序,所以java.base模块将总是排第一。
移除:签署标准的重写机制
签署标准的重写机制允许保持新版本标准外的Java程序社区的实现,或者独立API是Java SE平台的一部分还继续独立地发展,为了安装带运行时镜像。
签署标准的重写机制现在定义在依据系统属性,java.endorsed.dirs ,和默认值在JAVA_HOME/lib/endorsed。jar文件包含一个新的签署标准或独立API的实现,可以安装到运行时镜像代替其中一个命名在系统属性的文件,或者如果系统属性没有定义,替换它在默认的 lib/endorsed 目录。例如:jar文件添加到运行时JVM的bootstrap的类路径,从而覆盖了在运行时系统的任何定义存储。
一个模块化镜像是由模块组成的而不是jar文件。我们希望 支持背书标准和只能从独立API在模块中,各种可升级模块组成。我们因此建议移除 系统属性java.endorsed.dirs,lib/endorsed目录和机制的实现代码。为了识别任何存在的机制使用,我们将修改编译器和启动失败如果系统属性是设置的或者如果lib/endorsed目录已经存在。
移除:扩展机制
扩展机制允许jar文件包含APIs,API扩展了Java SE平台并安装于运行时镜像,所以在镜像中它们内容对任何编译和运行的应用都是可见的。
机制定义定义在类似path的系统属性java.ext.dirs,一个默认值是$JAVA_HOME/lib/ext组成的,和一个平台指定系统宽度目录(例如:在linux中/usr/java/packages/lib/ext)。工作在很多一样的方式正如文档标准机制除了jar文件所在扩展目录是被运行镜像环境扩展类加载器加载,bootstrap class加载和父级系统类加载器,从class path中加载应用程序而运行。扩展类因此不能通过bootstrap类加载器重写jdk的类,但是它们的加载方式优先于系统加载程序及其子类定义的类。
扩展机制是在JDK 1.2中被介绍的,发布在1998年,但是现在我们看到的它使用的一小部分。这不是惊喜的,现在很多java应用程序使用这些类库,它们需要指引到class path而不是类库安装,作为一个运行时系统的扩展。
技术上可能,通过令人尴尬的,为了继续支持在模块JDK中的扩展机制。为了简化Java SE平台和JDK,问我们支持移除java.ext.dirs系统属性,lib/ext目录,和机制的代码实现。为了帮助识别任何存在的机制使用,我们将修改编译器和启动失败如果这系统属性被设置了或者如果lib/ext目录存在。编译器和启动器将忽略平台指定的系统宽度扩展目录而使用默认的,但是如果-XX:+CheckEndorsedAndExtDirs命令行选项是指定的那么他们讲失败如果目录已经存在和或者不是空的。
几个特性与扩展机制相关将保留,因为它们在这里面是好用的:
- Class-Path 的mainfest属性,指定jar文件需要另一个jar文件。
- {Specification,Implementation}-{Title,Version,Vendor} mainfest属性,指定了包和jar文件的版本信息。
- Sealed mainfest属性,封闭了一个包或者jar文件等
- 通过它扩展类加载器
扩展类加载器将被保留为了保持兼容性。为了一个类Foo类通过系统加载器加载,原则上,表达式:
Foo.class.getClassLoader().getParent() != null
将保留。
移除:rt.jar和tools.jar
类和资源文件以前存储在lib/rt,lib/tools.jar,lib/dt.jar和各种其他内部jar文件现在将被存储到一个很多高效率格式的实现文件的lib目录。文件的格式将不被指定和并随时改变,如不另行通知。
rt.jar的去除和相似文件导致了3个问题:
- 存在标准APIs例如ClassLoader::getSystemResource方法返回URL对象来命名类和资源文件在运行时镜像里。例子,当运行jdk8的代码
ClassLoader.getSystemResource("java/lang/Class.class");
returns a jar URL of the form
jar:file:/usr/local/jdk8/jre/lib/rt.jar!/java/lang/Class.class
,当可以被看到的,嵌入一个文件URL来命名一个确切的jar文件在运行时镜像的内部。URL对象的getContent方法可以被用于检索类文件的内容,通过构建协议处理jar URL的方案。
模块镜像将不包含任何jar文件,所以上面的URLs形式毫无意义。getSystemResource的指定和相关的方法,幸运滴不需要通过这些方法返回URL对象,而确切使用了jar方案。他们做,无论如何,这可能要加载一个存储类或资源文件的内容通过URL对象。
- java.security.CodeSource API和security-policy files 使用URL来命名基础代码的路径,而被授予指定的权限。运行时镜像系统的组件需要指定权限许可在lib/security/java.policy文件通过文件URLs。elliptic-curve密码提供者,例如,许可在
file:${java.home}/lib/ext/sunec.jar
明显地,将没有意义在一个模块镜像中。
- IDEs和其他类型的开发工具需要枚举类和资源存储在一个运行时镜像,和为了读它们内容。今天它们引导而打开和阅读rt.jar和相似的文件。这样当然不可能是一个模块化镜像。
新的URL 方案类命名存储模块,类和资源
为了解决上述的三个问题,我们需要定义新的URL方案,jrt,为了命名这个模块,了和资源存储在运行时镜像而没有揭示内部结构或者镜像的格式。
一个jrt URL是分层的URI,RFC 3986,和语法
jrt:/[$MODULE[/$PATH]]
在$MODEL是一个可选模块名和$PATH,如果现有是path指定诶或者资源文件在模块内部。jrt URL意味着依靠它之前的结构:
- jrt:/$MODULE/$PATH引用指定类或资源文件命名在$PATH内部为了$MODLE.
- jrt:$MODLE引用所有内核资源文件在$MODLE模块。
- jrt:/ 引用整个类和资源集合存储在当前的运行时镜像。
这三个jrt URL表单解决了上面的问题,如下:
- APIs现在返回jar URLs而将返回jrt URLs。上面类加载器调用::getSystemResource ,等等,将返回URL
jrt:/java.base/java/lang/Class.class
一个构建协议处理了jrt方案将被定义,所以类似URL对象getContent 方法 检索命名类和资源文件的内容。
- 收保护文件和其他源代码API的使用可以用于jrt URLs来命名指定模块,为了 授权。椭圆曲线密码提供者,例如现在可以确定jrt的URL。
jrt:/jdk.crypto.ec
当前授于所有权限的其他模块,但是事实上并他们不需要普通的特权。
- 一个构建在NIO文件系统提供者将被定义为jrt URL的解决方案所以开发工具可以枚举和读取class和资源文件,通过运行时镜像加载的被URL jrt命名的文件系统:/。例子:
FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
byte[] jlo = Files.readAllBytes(fs.getPath("java.base",
"java/lang/Object.class"));
为了工具支持JDK9的开发代码但是它们是运行在JDK8上,拷贝了文件系统提供者适配的JDK8,未来将会在根目录替换为JDK9的运行镜像在一个命名为 jrt-fs.jar的文件。
(jrt URL协议处理器将不返回任何第二和第三的URL内容)
构建系统改变
构建系统将会被修改为生产新的运行时镜像格式如上面的描述。我们在这里也借此机会,最终将分别地重命名images/j2sdk-image,images/j2re-image,和images/j2re-compact$N。
镜像规范改变
JEP 162,实现在了JDK8,很多改变是为了准备Java SE平台和JDK的模块化工作和在最近的JEP中。在这些改变中去除一些规范声明,这需要确定配置文件可以在运行时镜像的lib目录被找到,这些文件在配置中将被替换。很多SE API声明修订后作为Java SE 8的一部分,但是一些API则共享到Java SE和EE平台中,例如一下声明:
- javax.xml.stream.XMLInputFactory specifies ${java.home}/lib/stax.properties (JSR 173)
- javax.xml.ws.spi.Provider specifies ${java.home}/lib/jaxws.properties (JSR 224).
- javax.xml.soap.MessageFactory, and related classes, specify ${java.home}/lib/jaxm.properties (JSR 67).
这些声明将不会授权于lib目录正如现在修改的。
开放问题
- 如何改变字体,可能还需要调整。
- lib/security目录依然包含两个jar文件,它们的内容是简单本地和US导入的密码规则文件;我们注意到替换这些jar文件和它们的内容。(8061842)
- lib/$ARCH文件是目前只能在Linux和Solaris上构建的。这是残留镜像可以支持多核CPU,只是这不再是一个需求了。我们将电池它的内容在lib目录中是否能被代替,在Mac OS和Windows也是一样的,而不再需要lib/$ARCH目录(8066474)(不再是开发问题;不再有lib/$arch目录)
- 例子、样板和人工目录的内容应该理想地来自适当的模块;我们将调查怎么做是最好的。(8066476)
- javax.activation.MailcapCommandMap类文件和最近累文件,指定了 ${java.home}/lib/mailmap(JSR 925);这需要被修订所以不授权于lib目录。
测试
一些已经存在的测试在运行时镜像的内部可用直接使用(例如,rt.jar)或者参考系统配置文件(例如:java.ext.dirs)现在已经不存在了。这些测试用例将被修订。
我们计划发布早的构建包含这些改变和故里java社区的成员来测试自己工具、类库和应用程序,这些构建可以帮助人们梳理任何剩下的兼容性问题。
风险和假设
中心风险的建议是兼容性,假设如下:
- 一个JDK镜像,将如上描述,不在包含一个jre子目录。已经存在的代码,假设使用在目录中的内容可能运行部正确。
- 系统属性 java.endorsed.dirs和java.ext.dirs将如上描述,不在被定义。已存在的代码假设使用了这些属性而获取null值可能就不能正常工作了。
- JDK和JRE镜像将如上面所说的,不在包含lib/rt.jar, lib/tools.jar, lib/dt.jar和其他内部jar文件。已经在的代码假设使用了这些文件可能就不能正常工作了。
- 已经存在的标准API返回了URL对象来命名class和资源文件在运行时镜像中,如上面描述的,现在返回jrt URLs。已存在的代码可以使用这些API来返回JAR的URL,这可能就不能正常工作。正如这些代码,例子:已经在Glassfinsh应用服务中发现了。
- 内部系统属性 sun.boot.class.path将不再命名序列的jar文件和目录。已存在的代码如果依赖这属性可能就不能正常工作了。
- 类和资源文件以前可以在lib/tools.jar中找到,现在当这jar加入class path中才可见,现在在JDK镜像,将可以通过系统类加载器或者bootstrap类加载器看到。模块包含这些文件将不能,无论如何,在应用程序的类路径中提到,等等,值在系统属性java.class.path.
- 类和资源文件以前可以在lib/dt.jar找到,现在当这jar加入class path中才可见,通过bootstrap类加载器,还有JRE和JDK。
- 定义类加载器类型在一些存在的包将会改变。已经存在的代码假设使用到了关于类加载器的类型可能就不能正确工作了。 具体的改变如下:
Package | Old loader | New loader |
---|---|---|
—————————– | ———– | ———– |
com.sun.crypto | extension | boot |
com.sun.jndi.dns | boot | extension |
com.sun.jndi.url.dns | boot | extension |
com.sun.tools.corba.se.idl | application | boot |
com.sun.tools.script | application | boot |
com.sun.tracing | boot | application |
sun.security.tools.policytool | boot | application |
sun.tools.jar | boot | application |
sun.tracing.dtrace | boot | application |
这些改变包含了API和组件的模块化的结果。组件的类文件从历史上看划分在了rt.jar和tools.jar,但是现在所有类文件将在一个模块里。
- 在JER镜像的bin 目录将包含少量的命令,以前只能在JDK镜像中找到的,名字为appletviewer, idlj, java-rmi.cgi, jrunscript, 何 jstatd。和前一个项目一样,这些改变包含了API和组件的模块化的结果。
这不可能决定于这些抽象改变的所有影响。我们必须因此依靠上面广泛的内部和特别是外部测试用例。精致的应用程序就像是IDE,比简易的类库和简单的应用更容易受到这些变化的影响。如果一些改变对于了开发者、发布者或者最终使用者是不可逾越的障碍,那么我们将调查如何减轻对他们的影响。
依赖
JEP 是四分之三的Jigsaw项目。它依赖于,重组了JDK源在模块和升级构建系统来编译模块。这也依赖于更早的准备工作,在JEP 162已经做了。实现在JDK8。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/99767.html