New Features Of JDK - JDK9 Modular System

news2024/9/29 13:41:55

 

Modular System 是 JAVA9 中提供的新特性,它从一个独立的开源项目而来,名为 Jigsaw Project。在此之前,我们对于 Java 技术栈中模块化的认知是基于 OSGI 的,实际上 OSGI 也确实形成了它自己独有的体系,并且是一定程度上的行业标准。

JAVA 模块化发展

JAVA 从没有停止过在模块化事情上的努力,比如 JSR 294 提出的 superpackages,JSR 277 中的 Java Module System(后来被 JSR 376 替换掉了);直到 Jigsaw 这个原型项目的出现,这个原本计划在 Java7 一起交付的功能,也一直被推迟到 Java9 才提供出来;作为原型项目,Jigsaw 提供了 JPMS(Java Platform Module System) 规范的参考实现。

另一个是独立于 Java 社区发展的 OGSI。到目前为止,OSGi 已经发展超过 20 年,OSGi 是应用程序模块化的事实标准。一方面 OGSI 不是 Java 平台的直接组成部分,所以它不会影响平台本身的模块化发展,另一个重要的因素则是 OSGi 使用的是类加载器实现的模块化隔离,这与 Jigsaw 基于可访问性规则实现的隔离机制完全不同。

话说回来,为什么模块化会如此的重要呢?

首先是 JAVA 自身的不断臃肿,从 JAVA 1.1 的小于 10M 到 JAVA 8 的 200M+,不管是安装占用空间还是内存要求都有相应增加,这个增加虽说是由新功能的迭代带来的,并且这些新功能中的绝大部分是受欢迎的;但是换个角度说,每一项新功能都会为不需要它的用户造成膨胀,可以肯定的是,不会有哪个工程师或者哪个团队会使用到 Java 提供的所有能力(比如你做 web 项目,还不得不带上 swing)。

另一点,也是 OSGI 能够发展的原因,依托类加载器来实现业务层面的隔离,并且具备动态载入的能力,这也使得 plugin 机制或者热加载机制能够有非常大的发挥空间。

Java 9 中的 Module System

模块化的前提是模块划分,JDK 自身也进行了模块化的处理,具体可以见 openjdk.org/jeps/200

Java 9 的 Module System 到底是什么?官方说法是:模块化在包之上增加了更高级别的聚合,它包括一组密切相关的包和资源以及一个新的模块描述符文件。简单点说,它是一个 Java 包的包 抽象。

目前 Module System 有 4 种类型的模块,如下表所示

类型说明备注
系统模块Java SE 和 JDK 模块,通过 list-modules 可以看到完整列表/
应用程序模块业务自己定义的模块/
自动模块当将非模块 jar 添加到模块路径时,会创建具有 jar 名称的模块1、默认导出所有包 2、默认情况下可以访问所有其他模块的类
未命名模块当将 jar 或类添加到类路径时,所有这些类都会添加到未命名的模块中1、只导出到其他未命名的模块和自动模块。这意味着,应用程序模块无法访问这些类 2、它可以访问所有模块的类

下面我们通过一个小案例来直观的体验下模块化,也就是上表中的 应用程序模块

模块案例

这个案例中包含两个模块,glmapper.modules 模块用于导出自己的服务,test.modules 模块用来测试引用第一个模块。

模块1 - glmapper.modules

  • 创建项目文件夹
mkdir my-project
cd my-project
复制代码
  • 创建模块目录
mkdir my-module 
复制代码
  • 在 my-module 目录下创建 glmapper.modules
mkdir glmapper.modules 
复制代码
  • 在模块下创建 package
com.glmapper.bridge.boot
复制代码
  • 包中创建一个名为 HelloModules.java的新类
package com.glmapper.bridge.boot;

public class HelloModules {
    public static void sayHello() {
        System.out.println("Hello, Glmapper Modules!");
    }
}
复制代码
  • glmapper.modules根目录中添加模块描述符 module-info.java
module glmapper.modules {
    // 导出 com.glmapper.bridge.boot 包的所有公共成员
    exports com.glmapper.bridge.boot;
}
复制代码

此时的文件目录大致如下:

└── my-module
    └── glmapper.modules
        ├── com
        │   └── glmapper
        │       └── bridge
        │           └── boot
        │               └── HelloModules.java
        └── module-info.java
复制代码

模块2 - test.modules

  • 在 my-module 下创建 test.modules 模块
mkdir test.modules
复制代码
  • 创建模块描述符文件 module-info.java
module test.modules {
    requires glmapper.modules;
}
复制代码
  • 创建 com.glmapper.bridge.main 包,并创建一个 TestMain.java 文件
package com.glmapper.bridge.main;
// 导入 glmapper.modules 的类依赖
import com.glmapper.bridge.boot.HelloModules;

public class TestMain {
    public static void main(String[] args) {
        // 调用依赖类的静态方法
        HelloModules.sayHello();
    }
}
复制代码

此时的目录结构如下:

└── my-module
    ├── glmapper.modules
    │   ├── com
    │   │   └── glmapper
    │   │       └── bridge
    │   │           └── boot
    │   │               └── HelloModules.java
    │   └── module-info.java
    └── test.modules
        ├── com
        │   └── glmapper
        │       └── bridge
        │           └── main
        │               └── TestMain.java
        └── module-info.java
复制代码

构建运行模块

  • 构建模块()
// modules 是构建产物的输出目录
javac -d modules --module-source-path my-module $(find my-module -name "*.java")
复制代码
  • 构建之后的目录结构如下
├── modules // 构建产物所在的目录
│   ├── glmapper.modules
│   │   ├── com
│   │   │   └── glmapper
│   │   │       └── bridge
│   │   │           └── boot
│   │   │               └── HelloModules.class
│   │   └── module-info.class
│   └── test.modules
│       ├── com
│       │   └── glmapper
│       │       └── bridge
│       │           └── main
│       │               └── TestMain.class
│       └── module-info.class
└── my-module
    ├── glmapper.modules
    │   ├── com
    │   │   └── glmapper
    │   │       └── bridge
    │   │           └── boot
    │   │               └── HelloModules.java
    │   └── module-info.java
    └── test.modules
        ├── com
        │   └── glmapper
        │       └── bridge
        │           └── main
        │               └── TestMain.java
        └── module-info.java
复制代码
  • 运行代码
# 运行模块需要指定 模块路径和主类 
> java --module-path modules -m test.modules/com.glmapper.bridge.main.TestMain
> Hello, Glmapper Modules!
复制代码

可以看到,我们得到了正确的结果。

那么我们再来测试一种场景,就是在 glmapper.modules 中不导出包,重新构建时得到的结果如下:

my-module/test.modules/com/glmapper/bridge/main/TestMain.java:3: 错误: 程序包 
com.glmapper.bridge.boot 不可见
import com.glmapper.bridge.boot.HelloModules;
                          ^
  (程序包 com.glmapper.bridge.boot 已在模块 glmapper.modules 中声明, 但该模块未导出它)
1 个错误
复制代码

可以看到,当编译 test.modules 时,会检测出它所依赖的模块中的 package 是否被导出,如果没有导出那么就无法通过编译。

接口使用

上面案例中,为了便于测试,是在模块中提供了一个可访问的静态方法;下面我们继续改造,在 glmapper.modules 中提供 interface 以及 interface 的实现,并通过使用 provides...with 和 uses 指令来实现和 test.modules 模块的交互引用。

  • 在 glmapper.modules 中提供一个 HelloService 接口
package com.glmapper.bridge.boot;
public interface HelloService {
    void helloWorld();
}
复制代码
  • HelloService 接口实现类 HelloServiceImpl
package com.glmapper.bridge.boot.impl;

import com.glmapper.bridge.boot.HelloService;

public class HelloServiceImpl implements HelloService {

    public void helloWorld() {
        System.out.println("Hello World...");
    }
}
复制代码
  • 修改 glmapper.modules/module-info.java
module glmapper.modules {
    // 导出 com.glmapper.bridge.boot 包的所有公共成员
    exports com.glmapper.bridge.boot;
    provides com.glmapper.bridge.boot.HelloService with com.glmapper.bridge.boot.impl.HelloServiceImpl;
}
复制代码
  • 修改 test.modules/module-info.java
module test.modules {
    requires glmapper.modules;
    uses com.glmapper.bridge.boot.HelloService;
}
复制代码
  • 修改 TestMain
package com.glmapper.bridge.main;

import com.glmapper.bridge.boot.HelloModules;
import com.glmapper.bridge.boot.HelloService;
import com.glmapper.bridge.boot.impl.HelloServiceImpl;
import java.util.ServiceLoader;

public class TestMain {
    public static void main(String[] args) {
        HelloModules.sayHello();
        // 这里可以通过 ServiceLoader SPI 方式来调用的
        Iterable<HelloService> services = ServiceLoader.load(HelloService.class);
        HelloService service = services.iterator().next();
        service.helloWorld();
        
        // 通过实例化对象调用
        HelloService helloService = new HelloServiceImpl();
        helloService.helloWorld();
    }
}
复制代码
  • 重新编译并执行
> java --module-path modules -m test.modules/com.glmapper.bridge.main.TestMain    
> Hello, Glmapper Modules!
  Hello World...
  Hello World...
复制代码

小坑

module-info.java 中导出包不能支持对其子包的导出

module glmapper.modules {
    // 导出 com.glmapper.bridge.boot 包的所有公共成员
    exports com.glmapper.bridge.boot;
    // 这里需要 com.glmapper.bridge.boot.impl,否则 impl 子包中的内容对 test.modules 不可用
    exports com.glmapper.bridge.boot.impl;
    provides com.glmapper.bridge.boot.HelloService with
    com.glmapper.bridge.boot.impl.HelloServiceImpl;
}
复制代码

总结

本文对 Java 模块化进行了介绍,通过本文你可以大体了解到 Java 模块化发展的基本情况,了解 Java 9 提供的模块化能力和 OSGI 模块化能力的差异。然后我通过一个案例向你介绍了 Java 模块化的基本使用方式,希望对你能够有所帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/55055.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TFT espi相关

文章目录1 .库文件设置1-1&#xff1a;这是库文件 tft _espi1-2&#xff1a;如何确定像素排列方式1-3&#xff1a;颜色显示异常处理方法2 .显示图片3.显示图片方法1 .库文件设置 1-1&#xff1a;这是库文件 tft _espi 链接&#xff1a;https://pan.baidu.com/s/1sT6s6VtpuwNV…

Spring【五大类注解的存储和读取Bean方法注解】

Spring【5大类注解的存储和读取Bean对象】&#x1f34e;一. 五大类存储 Bean 对象&#x1f352;1.1 配置spring-config.xml扫描路径&#x1f352;1.2 添加五大类注解存储 Bean 对象&#x1f349;1.2.1 Controller&#xff08;控制器存储&#xff09;&#x1f349;1.2.2 Service…

ADAU1860调试心得(14)单片机启动与控制ADAU1860详解

ADAU1860实现脱机运行&#xff0c;是开发这个DSP的最后一步。这颗芯片有一颗HIFI 3Z的蓝牙MCU内嵌&#xff0c;用户可以用这颗MCU来进行脱机&#xff0c;甚至直接用C来开发1860&#xff08;有专门的SDK&#xff0c;不在此做更多阐述&#xff09;&#xff0c;但是这个HIFI 3Z的软…

零代码使用air32做USB转串口

零代码实现USB转串口 环境搭建参考Air32F103使用手册 创建工程 新建工程 选择设备为AIR32F103CB 在弹出的RTE窗口勾选如下组件 配置工程 修改编译器为AC5&#xff0c;并启用MicroLIB 启用C99标准支持 添加代码 添加功能代码&#xff0c;在Source Group文件夹右键&#xff…

观测云产品更新|应用性能新增服务清单功能;用户访问监测 Session 查看器调整;事件新增移动端跳转选项等

观测云更新 应用性能新增服务清单功能 应用性能监测服务清单&#xff0c;支持实时查看不同服务的所有权、依赖关系、性能、关联的仪表版以及关联分析&#xff0c;快速发现和解决服务的性能问题&#xff0c;帮助团队高效地构建及管理大规模的端到端的分布式应用。 更多详情可…

FineReport可视化数据图表- 函数计算组成和语法示例

1.1设计报表 例如&#xff0c;使用内置数据集「销量」创建数据集ds1&#xff0c;对不同地区销量高低做判断。 将「地区」字段拖入 A2&#xff0c;将「销量」字段拖入B2&#xff0c;并设置「销量」展示方式为求和&#xff0c;然后对不同地区的销量情况进行求和&#xff0c;如下…

【吴恩达机器学习笔记】九、机器学习系统的设计

✍个人博客&#xff1a;https://blog.csdn.net/Newin2020?spm1011.2415.3001.5343 &#x1f4e3;专栏定位&#xff1a;为学习吴恩达机器学习视频的同学提供的随堂笔记。 &#x1f4da;专栏简介&#xff1a;在这个专栏&#xff0c;我将整理吴恩达机器学习视频的所有内容的笔记&…

Allegro如何用list文件抓取器件操作指导

Allegro如何用list文件抓取器件操作指导 Allegro支持list文件在PCB上抓取器件,具体操作如下 在pcb相同目录下新建一个后缀为.lst文件,任意命名一个名字比如123.lst 原理图中批量选择需要抓取器件的信息,支持批量选择,无用的信息框选进去也是可以的 复制到新建lst文件中去…

主流嵌入式操作系统有哪些

嵌入式操作系统EOS(Embedded OperatingSystem)是一种用途广泛的系统软件&#xff0c;过去它主要应用于工业控制和国防系统领域。常见的嵌入式操作系统有wince、PALM OS、linux、Android、FreeRTOS。 WINDOWS CE是微软开发的一个开放的、可升级的32位嵌入式操作系统&#xff0c;…

【Matplotlib绘制图像大全】(二十六):Matplotlib读取本地图像

前言 大家好,我是阿光。 本专栏整理了《Matplotlib绘制图像大全》,内包含了各种常见的绘图方法,以及Matplotlib各种内置函数的使用方法,帮助我们快速便捷的绘制出数据图像。 正在更新中~ ✨ 🚨 我的项目环境: 平台:Windows10语言环境:python3.7编译器:PyCharmMatp…

基于SpringBoot和Vue的厨到家服务平台的设计与实现毕业设计源码063133

springboot厨到家服务系统 摘 要 在社会快速发展的影响下&#xff0c;餐饮迅速发展&#xff0c;大大增加了餐饮服务信息管理的数量、多样性、质量等等的要求&#xff0c;使餐饮的管理和运营比过去十年更加困难。依照这一现实为基础&#xff0c;设计一个快捷而又方便的厨到家服…

十二条后端开发经验分享,纯干货

前言 本文是博主从事后端开发以来&#xff0c;对公司、个人项目的经验总结&#xff0c;包含代码编写、功能推荐、第三方库使用及优雅配置等&#xff0c;希望大家看到都能有所收获 博主github地址: github.com/wayn111 一. 优雅的进行线程池异常处理 在Java开发中&#xff0c…

【Recurrent Neural Network(RNN)】循环神经网络——李宏毅机器学习阅读笔记

Recurrent Neural Network(RNN) Example Application Slot Filling 智慧订票系统&#xff1a; How to represent each word as a vector? 但是光这样&#xff0c;feedforward Network是无法solve这一问题的&#xff0c;因为他无法区别是leave Taipei还是arrive Taipei。…

stable diffusion webui安装部署教程

系统环境&#xff1a; 腾讯云服务器&#xff0c;centos 7.6 基础环境安装 git 安装&#xff08;直接安装高版本的&#xff09; (默认安装的是1.8 版本的。没有 -c 命令&#xff0c;需要升级&#xff09; 参考&#xff1a; https://blog.csdn.net/qq_28903377/article/detai…

[附源码]Python计算机毕业设计SSM康健医药公司进销存管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

[附源码]Python计算机毕业设计SSM酒店入住管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

计算机视觉专家:如何从C++转Python

有人说用 Python 编程很简单&#xff0c;6 岁小孩都能学会。计算机视觉专家和编程语言爱好者 asya f 刚开始上手 Python 时也这么想。但门槛低就仅意味着使用简单吗&#xff1f;经常调用 API 的人是不是一定比可以从零写出源码的人菜&#xff1f;在本文中&#xff0c;asya f 告…

数据生产流程——采集、清洗、分析

大家好&#xff0c;这里是小安说网控。 前几篇文章&#xff0c;我们分享了线上价格监测的重要性以及注意事项。数据监测是如何将平台上海量的数据转换为有价值的营销情报的呢&#xff1f;今天&#xff0c;我们来一个数据生产流程大揭秘&#xff01; 一、 数据采集 数据采集就是…

2022腾讯数字生态大会:腾讯云HiFlow,零代码自动化工作流助手

2022腾讯数字生态大会&#xff0c;在主题为“数字化叠变、全域新协作”的腾讯云SaaS连接专场上&#xff0c;多款产品重磅发布。 未来企业数字化转型的越来越多的使用saas是一个趋势&#xff0c;那么如何解决SaaS之间的互联互通和数据孤岛&#xff1f;腾讯云HiFlow的业务负责人…

嵌入式通用const和volatile和static inline关键字 (volatile寄存器地址修饰必不可少)

const和volatile之间的合作【1】const修饰变量【2】const修饰数组【3】const修饰指针【4】const修饰函数【5】volatile的应用【6】volatile详解【7】const和volatile配合【8】AHB (高级高性能总线)【9】APB (高级外围总线)在学习ADC之前掌握这些 #define __IO volatile …