java9 模块化
必要性
- 可定制的 JRE :更小的运行时镜像
- 更确定的模块依赖关系:避免 JAR HELL 问题
- 与 OSGI 的比较
定义
- 模块是一个命名的、自我描述的代码和数据的集合
- 模块的代码被组织成多个包,每个白中包含Java类和接口
- 模块的数据则包括资源文件和其他静态信息
模块声明文件
- 模块声明文件:module-info.java
- 关键词:module
模块依赖和包导出
- 导出包:exports
- 只导出所声明包中的类型
- 对于子包要显式声明
- 使用 to 来声明可以访问的模块名称
- 模块的依赖关系:requires
- 声明所依赖的包的名称
- 不允许出现重复模块
- 可以声明不存在的模块(不过编译器会给出警告)
- 受限导出:exports to
- exports
exports package.a;
导出该模块下的 package.a 包
exports package.a to module.b,module.c;
导出该模块下的 package.a 包,且仅限在另一个模块 module.b 和 module.c 使用
- requires
requires module.a;
引用 module.a 模块
requires transitive module.x; // 传递依赖
(transitive 意为传递的意思;)
module module.a{
requires transitive module.log;
}
module module.b{
requires module.a;
}
module.a 传递依赖 module.log;如果 module.b 依赖 module.a ,则 module.b 会依赖 module.log 模块;
requires static module.c;
可选依赖关系,在编译时模块依赖性是必需的,但在运行时是可选的。
- uses [interface]
uses package.MyInterface;
uses 用于声明需要的接口,这样就可以使用 java.util.ServiceLoader.load 方法去加载依赖中的 service provider ;
必须是本模块中的接口
,不能是其他模块中的。其实现类可以由其他模块提供。
- provides [interface] with [implement]
provides package.MyInterface with package.Impl1,package.Impl2;
声明了是 MyInterface 接口的服务提供方,好让模块系统知道这个模块提供了该接口的实现。
- 不需要exports这个实现类,即服务提供模块可以不用exports服务实现。
- [interface] 可以不是本模块中的类,但[implement]是本模块中的类
- opens
要反射公共字段,需要exports导出包,这是允许的最小可访问性。要反射非公共字段,必须打开opens该包,这是允许的最大可访问性。
(深层反射:简单来说就是可以通过反射访问非公共字段)
打开一个包意味着允许其他模块对该包中的类型使用深层反射。 可以打开一个包指定给所有其他模块或特定的模块列表。
opens ;
opens to , …;