java 9+通过module类和moduledescriptor动态获取模块元数据:class.getmodule()获模块实例,调用getname()、isnamed()及getdescriptor();后者提供version()、requires()、exports()等方法解析module-info声明内容,并支持modulelayer跨模块查询。

Java 在运行期间动态获取模块的元数据信息,主要依靠 Java 9 引入的模块系统(JPMS) 提供的 Module 类和相关反射 API。核心思路是:通过类、类加载器或模块层(ModuleLayer)拿到 Module 实例,再调用其方法读取模块名、导出包、依赖、服务、版本等信息。
通过类获取所属模块并读取基本信息
每个类在模块化环境中都归属于某个模块。可通过 Class.getModule() 获取其模块对象,这是最常用的方式:
-
module.getName():返回模块名(如"java.base"或自定义模块名) -
module.isNamed():判断是否为命名模块(非匿名模块,即module-info.class存在) -
module.getDescriptor():获取ModuleDescriptor,是元数据的核心入口
使用 ModuleDescriptor 解析完整元数据
ModuleDescriptor 封装了 module-info.java 中声明的所有结构化信息,支持安全、只读访问:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
descriptor.version():返回Optional<version></version>,对应module-info中的version "1.0" -
descriptor.requires():返回Set<requires></requires>,含依赖模块名、是否可选(static)、是否合成(transitive)等 -
descriptor.exports():返回Set<exports></exports>,含导出的包名、目标模块(限制导出)等 -
descriptor.opens():类似 exports,但用于反射开放(opens指令) -
descriptor.provides():返回Set<provides></provides>,对应provides ... with ...声明的服务实现 -
descriptor.uses():返回Set<string></string>,即该模块声明使用的服务类型(uses java.sql.Driver)
获取当前模块层与跨模块查询
若需查找其他模块(比如服务提供者所在模块),需借助 ModuleLayer:
-
ModuleLayer.boot():获取启动层(包含java.base等核心模块) -
ClassLoader.getUnnamedModule().getLayer():对非模块化类加载器,可能返回null;模块化应用中可通过Thread.currentThread().getContextClassLoader().getUnnamedModule().getLayer()尝试获取 -
layer.modules():遍历当前层所有模块 -
layer.findModule("com.example.myapp"):按名称查找特定模块(返回Optional<module></module>)
注意事项与常见问题
实际使用中需注意几点:
- 非模块化代码(无
module-info.class)加载的类,其getModule()返回的是 未命名模块(unnamed module),isNamed()为false,getDescriptor()抛UnsupportedOperationException - 模块名、版本、导出等信息在编译期固化,运行时不可修改;但可通过
--add-opens等 JVM 参数临时放宽反射限制,不影响ModuleDescriptor的只读视图 - 服务发现(
ServiceLoader)底层也依赖uses/provides元数据,但通常无需手动解析——直接用ServiceLoader.load(...)即可 - 若在 JDK 8 或更早环境运行,模块 API 不可用,需降级为传统 ClassLoader + MANIFEST.MF 方式(如
getClass().getPackage().getImplementationVersion())
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










