Java 9模块化关键字及应用场景
一、背景
Spring Boot 3.0最低要求jdk17,为跟上节奏储备知识。
二、简介
关键字 | 描述 | 应用场景 |
---|---|---|
module | 定义一个模块 | 代码隔离,依赖控制,代码可重用性 |
open module | 定义一个像java9之前的开放模块 | 像Java的旧版本那样允许完全反射 |
exports...to | 指定模块的一部分对外提供的包 | 限制代码对外可见性,防止包冲突 |
requires | 指定当前模块依赖的另一个模块 | 控制依赖,避免冲突,提高系统可靠性 |
requires static | 声明一组模块的静态依赖关系 | 编译时检查依赖关系,以确保程序在运行时能够正确地工作。这对于使用反射或动态类加载的程序特别有用,因为这些程序在编译时无法检测到某些依赖关系,需要在运行时才能动态地加载类。 |
opens...to | 类似于exports,但是会开放当前模块内的包访问权限,便于反射使用 | 某些框架、工具需要使用反射机制,但是反射机制需要访问私有成员 |
uses | 指定当前模块使用的服务类型 | 提供SPI机制支持,方便应用程序扩展 |
provides ...with | 指定当前模块提供的服务类型和实现类 | 提供SPI机制支持,方便应用程序扩展 |
Java 9模块化关键字应用场景:
- module:模块化开发,将代码分成多个模块,隔离不同模块的功能,增加代码可重用性。
- exports:限制代码对外可见性,防止包冲突,控制API的访问权限。
- requires:控制依赖,避免冲突,提高系统可靠性。避免类路径的问题,方便模块的重构和管理。
- opens:提供某些框架、工具需要使用反射机制,但是反射机制需要访问私有成员。
- uses:提供SPI机制支持,方便应用程序扩展。
- provides:提供SPI机制支持,方便应用程序扩展。
三、基础声明模块与引用
1. 声明一个模块
module com.example.myapp {
requires java.base;
requires com.example.mymodule;
}
上述代码定义了一个名为 com.example.myapp 的模块,该模块依赖于 java.base 和 com.example.mymodule 模块。
2.导出包
module com.example.myapp {
requires java.base;
requires com.example.mymodule;
exports com.example.myapp.api;
}
上述代码将 com.example.myapp.api 包导出到其他模块中,使其可以访问。
3.开放反射访问
module com.example.myapp {
requires java.base;
requires com.example.mymodule;
opens com.example.myapp.internal to com.example.anothermodule;
}
上述代码将 com.example.myapp.internal 包开放给 com.example.anothermodule 模块,以便其可以使用反射访问该包中的类和方法。
4.使用自定义模块路径
module com.example.myapp {
requires java.base;
requires com.example.mymodule;
exports com.example.myapp.api;
}
上述代码使用 modules 目录中的模块路径来运行 com.example.myapp.Main 类。
四、SPI声明与引用
1.声明所需服务
uses关键字用于指定模块所需的服务,它可以出现在模块描述文件(module-info.java)中。下面是一个示例:
module com.example.myapp {
requires java.base;
requires com.example.mymodule;
exports com.example.myapp.api;
}
在上面的示例中,my.module模块依赖于some.module模块,并使用了com.example.service.SomeService服务。
2.对外声明所提供服务
provides关键字用于指定模块提供的服务和实现,它也可以出现在模块描述文件(module-info.java)中。下面是一个示例:
module my.module {
provides com.example.service.SomeService with com.example.service.impl.MyServiceImpl;
}
在上面的示例中,my.module模块提供了com.example.service.SomeService服务,并使用了com.example.service.impl.MyServiceImpl实现。
使用了provides关键字的模块还需要使用uses关键字来指定所需的服务,例如:
public interface SomeService {
void sayHello();
}
public class MyServiceImplimplements SomeService {
public static void doSomething() {
System.out.println("Hello, Modules!");
}
public void sayHello() {
System.out.println("Hello!");
}
}
module my.module {
uses com.example.service.impl.MyServiceImpl;
}
Iterable<SomeService> services = ServiceLoader.load(SomeService.class);
SomeService service = services.iterator().next();
service.sayHello();
浮生潦草闲愁广,一听啤酒一口尽