# module-demo **Repository Path**: jayung/module-demo ## Basic Information - **Project Name**: module-demo - **Description**: Java模块化申明示例 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-04-24 - **Last Updated**: 2025-04-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 模块化的来历 JDK9之前,JDK是个巨大的单体结构,光rt.jar就达50M左右,里面包含了常用的类库,不管是写一个最简单的helloworld程序,还是写一个带有数据库操作的应用,都需要依赖一个完整的JDK,运行时需要依赖一个完整的JDK/JRE,java应用都得一个很重的运行时环境。 模块化的更多背景信息,可见2017年9月发布的JDK9特性一览: > https://openjdk.org/projects/jdk9/ ## JDK的模块化 Java9开始,JDK进行了模块化改造,把JDK划成了20多个module,主要有:java.base、java.sql、java.desktop等。下载到本地的运行环境里,JDK目录多了一个 jmods的目录,里面就是各module文件,后缀名是jmod。完整的JDK大小高达200多M,而各jmod则只有几M到十几M不等。 ## 模块化的意义 用JDK9作运行时环境时,支持java应用使用Java9的模块化申明,Java应用程序编译及运行时,不再需要完整的JDK,而是可以按需引用,且打包时,可以只将依赖了的module与java应用打成一个整体的发布包,相当于应用与裁剪后的JDK放在一起,大大方便了Java程序的部署,与模块化一起发布的还有jlink命令、以后之后JDK14简化打包的jpackage命令,部署者不需要操心用户的JDK版本,服务器上也不需要预装JDK。运行时只需要执行对应平台(Win/Linux/Mac)的启动程序即可。这对Java桌面程序、部署简化有积极意义。 ## 模块化语法 申明模块化的文件名是:module-info.java,文件名通常与顶层package目录平行。Idea等工具提供了快速创建module-info.java的右键菜单,和快速填充requires依赖的提示。 |关键词|含义|片段示例| |---|---|---| |module|声明一个模块的关键词,后面接模块名称|`module myapp.util {}`| |open|声明一个module为open,表示该module下所有的类允许被外部类反射,即开放了该module下所有类的反射权|`open module myapp.util {}`| |requires |声明要依赖的模块|`requires java.sql;`| |requires transitive |与requires的区别是requires加了transitive关键词表示传递依赖,第三方模块再依赖时`myapp.util`,不需要再写`myapp.util`的依赖了。|`requires transitive java.sql;`| |exports |声明要暴露当前应用package目录(不含二级目录),只有声明暴露的package下面的类,才能被其他module下面的类import|`exports com.myapp.util;`| |exports to |对指定的module暴露|`exports com.myapp.util to myapp.service;`| |opens|开放指定package目录反射权|`opens com.myapp.util;`| |opens to |只对指定module开放指定package目录的反射权|`opens com.myapp.util to myapp.service;`| |uses |声明一个SPI接口,例如JDBC的驱动包接口声明在Java9之后就用了module的SPI机制|`uses java.sql.Driver;`| |provides with |SPI接口声明包和实现包不在同一个module发生,provides则是声明该module下指定类实现了另一个module的SPI接口,例如HSQLDB实现了JDBC驱动包|`provides java.sql.Driver with org.hsqldb.jdbc.JDBCDriver;`| 完整示例: module-a ``` module fly.api { requires java.base; exports com.fly; exports com.fly.others; uses com.fly.Flyable; } ``` module-b ``` module fly.bird { requires fly.api; exports com.fly.bird; exports com.fly.bird.service to fly.api; provides com.fly.Flyable with com.fly.bird.BirdFly; opens com.fly.bird.service; } ``` ## 存量项目是否需要模块化 模块化改造因涉及到项目工程大量第三方的影响,如果该项目Maven依赖的第三方包没有做module改造,那么该项目工程也会受影响,正是这个原因,2017年推出来的模块化,直到现在,还没完成大规模普及,不过好消息是,主流的框架已经完成了模块化声明,只有少数还没完成,目前模块化正在加速普及中。 ## Java模块化与Maven的关系 两者没有直接关系,现有Maven依赖管理不受Java模块化影响,Maven是用来管理依赖jar和项目工程构建的,Java模块化依赖是编译及运行时的依赖声明。如果项目工程没有进行module-info声明,那么JDK会直接认为unamed module,运行时不受影响,引入依赖的jar包里的module-info.class则也不会起作用。 ## JDK17\JDK21使用反射 模块化后,Java官方对滥用反射进行了一定的限制,但并不是完全禁止。如果第三方框架或自身代码要反射java官方库,那么可以通过启动时指定参数即可: ``` --add-opens java.base/java.util=ALL-UNNAMED ``` ## 模块化对反射的影响 反射功能是Java的一大法宝,使得Java编程能力比一些其他静态语言强不少,很多基础框架都是通过反射进行元编程或者框架能力增强。不过,由于Java早期没有做限制,导致了不少三方库的大量滥用。Java模块化后,则对反射进行了规范,反射依然可以用,只是需要进行显式申明,有利于反射和被反射双方,而通过反射去修改Java官方库则是不被建议的,如果确有需要,则在JVM启动参数上进行模块开放申明。 ## 模块化展望 目前主流的框架,如spring、jakarta ee、slf4j、log4j、logback、jackson、gson、hikaricp、junit等基本完与了模块化申明,进两年模块化申明明显加速,预计再过一两年,除主流框架库外,其他大部分也会完成模块化声明。 而模块化对Java最大的意义是,终于更方便地对JDK库进行新陈代谢,把已经不用的java api做一个摸排、把滥用反射而不自知第三方库进行预告并敦促改进。 关于模块化声明更多示例代码见: > https://gitee.com/jayung/module-demo.git