当前位置: 首页 > 科技观察

Java模块化系统初探

时间:2023-03-13 03:02:07 科技观察

Java模块化系统从提出到现在经历了很长一段时间,直到2014年底才最终在JSR(JSR-376)中定型,这部分可能出现在Java9中。但从来没有一个工作原型。9月11日,OpenJDK发布的早期版本终于包含了Jigsaw项目。昨天,我的同事PaulBakker和我在JavaZone上讨论了Java模块化系统。整个讨论基于JSR-376需求文档和周围的一些宝贵信息。当我们在年初提议举办这个演示会时,我们毫不怀疑我们可以在这次会议上展示一个原型,但事情并没有像预期的那样发展。按照目前的情况,这个原型将在我们的报告结束后发布。这也意味着报告中的一些内容有些过时,但主要思想还是很新颖的。如果您对Java模块化系统解决方案一无所知,建议您在阅读本文之前阅读我们的报告。我们的报告介绍了当前的方法,并进一步将其与OSGi进行了比较。为什么要使用模块?什么是模块?为什么我们又需要它们?如需深入讨论,请阅读“模块系统状态”或查看我们的报告。对于那些不太了解这个领域的人,这里是Cliff的注释版本。我们都知道Java有jar文件。然而,实际上,这些只是包含一些类(classes)的压缩文件,而这些jar包都是包(packages)。当你使用一些不同的jar包来运行应用程序时(更复杂的程序也适用),你需要将它们放在指定的类路径下。然后默默祈祷。因为没有有效的工具可以帮助你知道你是否把应用程序需要的所有jar包都放到了classpath中。或者您可能无意中将相同的类文件(在不同的jar中)放入了您的类路径。类路径灾难(类似于DLL灾难)是真实存在的。这可能导致运行时出现不良行为。同时,我们无法在运行时知道jar中包含了哪些类。从JRE的角度来看,只有一堆类文件。其实jar包是相互依赖的,只是目前还不能将这种依赖记录到数据文件中。理想情况下,可以将类文件的具体实现隐藏在jar包中,只提供一些公共的API即可。Java中提出了模块化系统来解决这些问题:模块成为首先考虑的东西,它可以将实现细节打包,只暴露需要的接口。模块准确描述了它们可以提供哪些接口,以及它们需要哪些部分(依赖项)。由此,我们可以在开发过程中找出并处理依赖关系。模块体系大大提高了大型系统的可维护性、可靠性和安全性。至少JDK本身是缺少这样的系统的。使用这样的模块系统,可以自动构建模块图。此图仅包含您的应用程序需要运行的模块。安装JDK9预览版如果您想尝试自己编写示例代码,则需要安装包含Jigsaw原型的JDK9早期版本。在OSX上,您需要解压缩存档并将解压缩的目录移动到Library/Java/JavaVirtualMachines/。然后需要设置环境变量,将JAVA_HOME环境变量指向JDK9的目录。我使用非常好的setjdk脚本,它可以在命令窗口中启用Java安装的命令切换。您可能不想将此早期版本用作您的Java安装。您可以使用java-version确认安装已完成。输出如下所示:123javaversion"1.9.0-ea"Java(TM)SERuntimeEnvironment(build1.9.0-ea-jigsaw-nightly-h3337-20150908-b80)JavaHotSpot(TM)64-BitServerVM(构建1.9.0-ea-jigsaw-nightly-h3337-20150908-b80,混合模式)只要Jigsaw包含在输出中,您就可以开始了。文章背后的示例代码可以在https://github.com/sandermak/jigsaw-firstlook下载。一个简单的例子你仍然可以在类、jar包和类路径的“传统方式”中使用JDK9。但显然我们希望采用模块化方法。因此,我们将创建一个包含两个模块的项目:模块一使用模块二的代码。首先要做的是构建我们的项目,把两个模块分离好。然后,模块需要以module-info.java文件的形式添加元数据。我们的示例构建如下:1234567srcmodule1module-info.javacomtestTestClassModule1.javamodule2module-info.javacommoretestTestClassModule2.java,module2),这是您之前构建的。在这些“模块目录”中,您可以在根目录中看到module-info.java文件。另请注意,这两个类都在显式命名的包中。请看TestClassModule1的代码:12345678910111213packagecom.test;导入com.moretest.TestClassModule2;公共类TestClassModule1{publicstaticvoidmain(String[]args){System.out。println("你好,来自"+TestClassModule2.msg());}}看起来很普通吧?这里不涉及模块,而是导入了TestClassModule2,后面main函数会调用其中的msg()方法。1234567891011包com.moretest;publicclassTestClassModule2{publicstaticStringmsg(){返回“来自模块2!”;}}到目前为止,module-info.java是空的。编译Java模块现在进行下一步:编译我们的模块并关联源文件。为了完成这项工作,我们将引入一个新的javac编译参数:1javac-modulesourcepathsrc-dmods$(findsrc-name'*.java')在使用上述语句时,我们假设命令程序已经的父目录中的src文件夹中。-modulesourcepath参数使javac从传统编译模式进入模块模式。-d标志表示编译模块的输出目录。javac会将这些模块作为解压文件输出。如果我们随后想将这些模块用作jar,则需要一个单独的步骤。那么当我们调用上面的javac命令行时会发生什么呢?编译错误!12src/module1/module-info.java:1:error:expected'module'src/module2/module-info.java:1:error:expected'module'Theemptymodule-info.javafilecausedthiserror.因此,这些文件中会引入一些新的关键字,它们是模块中非常重要的部分。这些关键字的范围是module-info.java的定义部分。您还可以在java源文件中使用模块类型变量。我们采用了最小描述并更新了模块描述文件:1modulemodule1{}然后是模块2:1modulemodule2{}这些模块现在已准确命名,但不包含其他数据。再次编译会出现新的错误:1src/module1/com/test/TestClassModule1.java:3:error:TestClassModule2isnotvisiblebecausepackagecom.moretestisnotvisible包出现了!默认情况下,模块内的类或其他类型对外界是隐藏的。这就是javac不允许使用TestClassModule2的原因,即使它是一个公共类。如果我们仍然使用传统的基于类路径的编译,一切正常。当然,我们也可以通过显式对外暴露TestClassModule2来解决这个问题。module2中的module-info.java需要进行以下更改:12345modulemodule2{exportscom.moretest;这还不够。如果你编译修改后的那个,你会得到同样的错误。这是因为,尽管module2现在公开了所需的包(包含所有公共类型),但module1尚未声明其对module2的依赖性。我们也可以修改module1的module-info.java文件来解决这个问题:12345modulemodule1{requiresmodule2;通过指定名称,我们可以表达对其他模块的依赖,虽然在这些模块中导出的包是以.关于这个还有很多可以说的,但我不想在这个初步介绍中涵盖它。做完这一步后,我们第一次使用Jigsaw成功编译了多模块项目。打开/mods目录,可以看到编译好的东西被整齐的分成了两个目录。就是这样!运行只编译的模块化代码并不是很有趣。我们希望应用程序运行。幸运的是,JRE和JDK已经支持这个原型中的模块关联。这个应用可以通过指定模块路径而不是类路径来启动:1java-mpmods-mmodule1/com.test.TestClassModule1我们把模块路径指向mods文件夹,也就是编译时javac写的输出模块地方。而-m指出了最开始启动的模块,通过它可以逐步启动其他模块。我们还添加了初始化时需要调用的启动类的名称,运行结果如下:1Hifromfromfrommodule2!以后这部分的介绍会让大家初步了解Java9中的模块可以做什么,这部分还需要更多的探索。就像打包一样:除了jar包,很快就会有一种新的形式,叫做jmod。这个模块化系统还包括一个服务层,它可以通过接口绑定服务提供者和服务消费者。将此视为控制反转:模块系统承担服务注册管理器的角色。另外一个值得期待的地方就是JDK本身会如何使用模块化系统进行模块化。这有可能支持一些非常酷的技术,例如创建仅包含JDK和应用程序所需模块的运行时映像。好处是:占用空间少,可以有更多的选择来进行程序的整体优化,等等。这些前景非常光明。我的下一个尝试是将一个简单的OSGi应用程序(它使用一些模块和服务)移植到Java9模块系统。敬请关注!原文链接:dzone翻译:ImportNew.com-闵大伟翻译链接:http://www.importnew.com/16761.html