模块的主要作用有:
模块通过在模块根目录下的中 module-info.java 的指令来约束使用。
最好(或则是必须,没找到规定说明) moduleName 和文件夹名称一致,否则 javac 编译时提示 module 和预期的不一致
module moduleA { } 引入依赖
requires moduleB;
可加 transitive 来表示依赖传递,如 requires transitive moduleB; ,然后在 moduleC 中 requires moduleA; 后,那么在 moduleC 中可使用在 moduleB 中导出的类或接口。
exports packageFullName;
表示当别的模块( A ) requires 了当前模块,那么 packageFullName 这个包(及子孙包)里的 public 和 protected 的类和接口可在模块 A 里被访问使用。
可用 exports packageFullName to moduleA, moduleB; 来表示仅 moduleA 和 moduleB 可访问 packageFullName 。
provides full.name.Service with full.name.concreateService, full.name.concreateService2;
表示该模块向外提供 full.name.Service 的实现 full.name.concreateService 和 full.name.concreateService2 。
uses full.name.Service;
表示该模块需要使用 full.name.Service 。同时,不直接依赖具体的实现,而是使用抽象类或接口。然后搭配 ServiceLoader 或别的 IoC 工具来做依赖注入,从而达到和具体实现解耦的目的。
opens fullPackageName;
表示 fullPackageName 可被使用反射技术。也可使用 opens fullPackageName to moduleA, moduleB; 限定开放反射的范围。
open module moduleD {}; 表示整个模块都是开放的。
java --list-modules 查看 JDK 内置的模块
可通过 javac -d mods --module-source-path src $(find src -name "*.java") 来编译运行(多个模块), src 表示各模块所在的目录。
也可使用 javac -d dist --module-source-path src -m client 来编译指定的模块。
src ├── sample.client │ ├── module-info.java │ └── test │ └── client │ └── Main.java ├── sample.impl │ ├── module-info.java │ └── test │ └── impl │ └── AccessImpl.java ├── sample.model │ ├── module-info.java │ └── test │ └── model │ └── Person.java └── sample.service ├── module-info.java └── test └── service └── AccessService.java
module sample.model { exports test.model; opens test.model; } package test.model; public class Person { private String name; public Person(String name) { this.name = name; } @Override public String toString() { return "Person{name='" + name + "'}"; } public static void main(String args[]) { System.out.println("Person main"); } } module sample.service { requires transitive sample.model; exports test.service; } package test.service; import test.model.Person; public interface AccessService { String getName(Person person); } module sample.impl { requires sample.service; provides test.service.AccessService with test.impl.AccessImpl; } package test.impl; import test.model.Person; import test.service.AccessService; import java.lang.reflect.Field; public class AccessImpl implements AccessService { @Override public String getName(Person person) { try { return extract(person); } catch (Exception e) { throw new RuntimeException(e); } } private String extract(Person person) throws Exception { Field field = person.getClass().getDeclaredField("name"); field.setAccessible(true); return (String) field.get(person); } } module sample.client { requires sample.service; uses test.service.AccessService; } package test.client; import test.model.Person; import test.service.AccessService; import java.util.ServiceLoader; public class Main { public static void main(String[] args) { AccessService service = ServiceLoader .load(AccessService.class) .findFirst() .get(); Person person = new Person("John Doe"); String name = service.getName(person); assert name.equals("John Doe"); System.out.println(person); } } IDEA 中,由于本身有一个 module 的概念,搭配使用 Java 的 module 时,一个 IDEA 的 module 只能定义一个 module-info.java 。