关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » JAVA »Java 模块化系统初探

    Java 模块化系统初探

    2015-09-28 00:00:00 出处:ImportNew
    分享

    Java 模块化系统自提出以来经历了很长的时间,直到 2014 年晚些时候才最终以 JSR(JSR-376) 定稿,而且这个部分有可能在 Java 9 中出现。但是一直以来都没有可以使用的原型。9 月 11 日,OpenJDK 发布的早期构建版本终于包含了 Jigsaw 项目。

    昨天,我和同事 Paul Bakker 在 JavaZone 上对于 Java 模块化系统进行了讨论。整个讨论都建立在JSR-376 需求文档以及身边一些珍贵的信息上。在年初提出举行这个报告的时候,我们曾深信不疑地认为在这个会上我们能够展示一个原型,但是事情却没有按预想的那样发展。现在的情况是,这个原型将在我们的报告结束之后发布。这也意味着,报告中的一些内容已经有点过时了,但是主要的思想还是很有新意的。如果你对 Java 模块化系统方案一无所知的话,建议你在阅读这篇文章之前先去看一下我们的报告。我们的报告介绍了现在的方案,并进一步与 OSGi 进行了比较。

    为什么要使用模块?

    什么是模块?我们为什又需要它们?如果希望有一个深入的讨论,请阅读“State of the module system”或者看一下我们的报告。对这块还不是很了解的人来说,这里有Cliff 的注释版本。

    我们都知道 Java 有 jar 文件。但是,事实上这些都只是包含一些class(类)的压缩文件,这些 jar 包内部都是一些 package (包)。当你利用一些不同的 jar 包来运行应用程序的时候(复杂一点的程序也适用),你需要把它们放到指定的类路径中。然后默默祈祷。因为没有有效的工具来帮助你知道,你是否已经把应用所需要的 jar 包都放入类路径中了。或者有可能你在不经意间将同样的类文件(在不同的 jar 包中)都放入了类路径中。类路径灾难(类似于 DLL 灾难)是真实存在的。这会导致运行时出现糟糕的状况。同时,在运行时我们也无法得知 jar 中包含哪些类。从 JRE 角度来说只知道有一堆类文件。事实上 jar 包之间是相互依赖的,但目前还不能把这种依赖关系记录到数据文件中去。理想的情况是,你可以隐藏 jar 包中类文件具体的实现,只是提供一些公共的 API 。在 Java 中提出模块化系统就是为了解决这些问题的:

    模块成为首先要考虑的部分,它能够分装实现细节并且只暴露需要的接口。 模块准确地描述了他们能够提供的接口,以及他们的需要部分(依赖)。由此,我们可以在开发的过程中弄清和处理依赖关系。

    模块系统极大地提升了大型系统的可维护性、可靠性、安全性。至少 JDK 本身还缺少这样的系统。通过这样的模块系统,模块图能够自动地构建。这个图只包括了你的应用程序运行时所须要的模块。

    安装 JDK9 预览版

    如果你想亲自尝试编写示例代码,你需要安装包含 Jigsaw 原型的 JDK9 早期构建版本。在 OSX 上,你需要解压文档,然后把解压出来的目录移动到 Library/Java/JavavirtualMachines/ 下。然后你需要设置环境变量,将 JAVA_HOME 环境变量指向 JDK9 的目录。我使用了非常好用的setjdk 脚本,通过它可以在命令窗口中实现 Java 安装的命令切换。你很有可能不愿意使用这个早期构建版本作为你的 Java 安装版本。你可以通过 java -version 来确认安装完成。输出如下面所示:

    java version "1.9.0-ea"
    Java(TM) SE Runtime Environment (build 1.9.0-ea-jigsaw-nightly-h3337-20150908-b80)
    Java HotSpot(TM) 64-Bit Server VM (build 1.9.0-ea-jigsaw-nightly-h3337-20150908-b80, mixed mode)

    只要输出中包含 Jigsaw ,你就可以继续了。文章后面的示例代码可以去 https://github.com/sandermak/jigsaw-firstlook 下载。

    一个简单的例子

    你仍旧可以通过类、jar包以及类路径这样“传统方式”的方式来使用 JDK9 。但是明显地我们想要采用模块的方式。所以我们将创建一个包含两个模块的工程:模块一使用了模块二中的代码。

    首先要做的就是,构建我们的工程并把两个模块很好地区分开来。然后,模块中需要以 module-info.java 文件的形式添加元数据。我们的示例构建如下:

    src
      module1
         module-info.java
         comtestTestClassModule1.java
      module2
         module-info.java
         commoretestTestClassModule2.java

    接着,我们将介绍 package (包)层最顶上的一层(module1、 module2),这部分你在之前已经构建好了。在这些“模块目录”中,可以看到 module-info.java 文件在根目录下。此外请注意,这两个类都是在显示命名的包中的。

    请看 TestClassModule1 的代码:

    package com.test;
    
    import com.moretest.TestClassModule2;
    
    public class TestClassModule1 {
    
       public static void main(String[] args) {
    
         System.out.println("Hi from " + TestClassModule2.msg());
    
       }
    
    }

    看起来很普通对吧?这里并没有涉及模块,而是导入了 TestClassModule2 ,主函数之后会去调用其中的 msg() 方法。

    package com.moretest;
    
    public class TestClassModule2 {
    
       public static String msg() {
    
         return "from module 2!";
    
       }
    
    }

    到目前为止,module-info.java 还是空的。

    对 Java 模块进行编译

    现在进行下一步:编译我们的模块,并关联源文件。为了做这项工作,我们将介绍一个新的 javac 编译参数:

    javac -modulesourcepath src -d mods $(find src -name '*.java')

    使用上面语句时,我们假设命令程序已经处于 src 文件夹的上级目录中了。-modulesourcepath 参数会让 javac 从传统编译模式进入模块模式。-d 标记指出了编译好的模块的输出目录。javac 将以非打包文件的形式输出这些模块。如果我们这之后想以 jars 的形式使用这些模块的话,需要一个单独的步骤。

    那么当我们调用上面的 javac 命令行的时候会发生什么那?编译出错了!

    src/module1/module-info.java:1: error: expected 'module'
    src/module2/module-info.java:1: error: expected 'module'

    空的 module-info.java 文件导致了这个错误。所以,一些新的关键字将被引入到这些文件中来,这些都是模块中非常重要的部分。这些关键字的作用域就是 module-info.java 的定义部分。你还可以在 java 的源文件中使用 module 类型的变量。

    我们采用了最少的描述信息,并更新了模块描述文件:

    module module1 { }

    然后是模块2:

    module module2{ }

    现在,模块已经被准确地命名了,但是还没有包含其它的数据。再次编译会导致新的错误:

    src/module1/com/test/TestClassModule1.java:3: error: TestClassModule2 is not visible because package com.moretest is not visible

    封装出现了!默认情况下,模块内部的类或者其他类型对外都是隐藏的。这就是 javac 不允许使用 TestClassModule2 的原因,即使它是一个公共的类。如果我们还是使用基于传统类路径的编译的话,一切都可以正常运作。当然我们也可以通过明确地将 TestClassModule2 暴露给外部来解决这个问题。接下来的这些改变对于 module2 中的 module-info.java 来说是必须的:

    module module2 {
    
      exports com.moretest;
    
    }

    这还不够。如果你将修改后的编译,你会得到同样的错误。那是因为,虽然现在 module2 已经暴露了所需的包(包含所有的公共类型),但是 module1 还没有声明它对 module2 的依赖。我们同样可以改变 module1 的 module-info.java 文件来解决这个问题:

    module module1 {
    
       requires module2;
    
    }

    通过指定名字的方法可以表示对其它模块的依赖,尽管在这些模块中是以包的形式导出的。这方面还有很多可以说的东西,但是我并不想在初步的介绍中涉及。在做完这一步之后,我们使用 Jigsaw 第一次成功编译了多模块项目。如果你打开 /mods 目录,你能看到编译出来的东西被整齐地划分为两个目录。这就成功了!

    运行模块化代码

    只是编译的话并没有多大乐趣。我们希望应用程序能够运行起来。幸运的是,JRE 和 JDK 已经在这个原型中支持模块关联。这个应用可以通过指定模块路径的方式来启动,而不是类路径:

    java -mp mods -m module1/com.test.TestClassModule1

    我们把模块路径指向 mods 文件夹,这个文件就是 javac 编译时写输出模块的地方。而 -m 指出了最初要启动的模块,通过这个模块可以逐步启动其他模块。我们同样添加了在初始化时需要调用的启动类的名字,运行结果如下所示:

    Hi from from module 2!

    未来

    这部分介绍可以让你初步了解可以使用 Java 9 中的模块可以做什么。这部分还是需要更多的探索。就像打包一样:除了jar包,即将会有一种新的形式叫做 jmod 。这个模块化系统同样包括一个服务层,它可以通过接口绑定服务提供者和服务使用者。可以把这个看成反转控制:模块系统担任服务注册管理的角色。还有一个值得期待的地方是,JDK 本身将会如何使用模块化系统进行模块化。这有可能支持一些非常棒的技术,比如创建一个运行时镜像,这个镜像可以只包括 JDK 和你应用所需要的那些模块。好处有:占用更少的空间,对于程序整体的优化可以有更多的选择等等。这些前景都是很光明的。

    我接下来将尝试移植一个简单的 OSGi 应用程序(该程序会使用一些模块和服务)到 Java 9 模块系统上。敬请关注!

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    帝国CMS7.5编辑器上传图片取消宽高的三种方法

    帝国cms如何自动生成缩略图的实现方法

    Windows 12即将到来,将彻底改变人机交互

    帝国CMS 7.5忘记登陆账号密码怎么办?可以phpmyadmin中重置管理员密码

    帝国CMS 7.5 后台编辑器换行,修改回车键br换行为p标签

    Windows 11 版本与 Windows 10比较,新功能一览

    Windows 11激活产品密钥收集及专业版激活方法

    如何从 Windows 11 中完全删除/卸载 OneNote?无解!

    抖音安全与信任开放日:揭秘推荐算法,告别单一标签依赖

    ultraedit编辑器打开文件时,总是提示是否转换为DOS格式,如何关闭?

    IT头条

    华为Pura80系列新机预热,余承东力赞其复杂光线下的视频拍摄实力

    01:28

    阿里千问3开源首战告捷:全球下载破千万,国产AI模型崛起新高度!

    01:22

    DeepSeek R1小版本试升级:网友实测编程能力已达到国际一线水平

    23:15

    NVIDIA 与 Dell 合作,大规模交付 Blackwell AI 系统

    20:52

    Cerebras 以最快的 Llama 4 Maverick 性能引领 LLM 推理竞赛

    20:51

    技术热点

    PHP中的随机性——你觉得自己幸运吗?

    搞定Ubuntu Linux下WPA无线上网

    Java使用内存映射实现大文件的上传

    MySQL安全性指南

    MySQL两项性能的基本测试浅谈

    教您使用UniqueIdentifier选取SQL Server主键

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。