模块的主要作用有:
模块通过在模块根目录下的中 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 。