java 模块化
java9出了模块,作为一名主要用java的程序员,所以要提前学习,保持一颗好学的心.
1.创建模块
新建java project com.horstmann.greet,eclipse新版会提示是否要创建模块,
,如果在此输入模块名字的话就会生成一个module-info.java类,是模块的描述信息类,主要包含以下内容
到此一个模块就创建好了,如果没有在创建的时候输入模块,也可以自己新建module-info.java类来创建模块.
2. 暴露模块
我们创建一个接口
package com.horstmann.greet; public interface Greeter { static Greeter newInstance() { return new com.horstmann.greet.internal.GreeterImpl(); } String greet(String subject); }
和它的实现类
package com.horstmann.greet.internal; import com.horstmann.greet.Greeter; public class GreeterImpl implements Greeter { @Override public String greet(String subject) { // TODO Auto-generated method stub return "Hello, " + subject + "!"; } }
目录结构如下
一般来说都会暴露模块的接口,而不是实现类,类似于es6中的模块,我们直接exports包即可
module com.horstmann.greet {
exports com.horstmann.greet;
}
这样其他模块就可以引用即可
3.引用暴露的模块
新建模块 v2ch09.exportedpkg
创建类HelloWorld
在eclipse中右键属性引入刚刚的模块
编辑module-info.java即可引入导出的类
module v2ch09.exportedpkg {
requires com.horstmann.greet;
requires hellomod.test;
}
public class HelloWorld { public static void main(String[] args) { Greeter greeter = Greeter.newInstance(); System.out.println(greeter.greet("Modular World")); } }
直接运行helloworld类,即可看到结果
通过exports和requires,我们可以在module-info中对模块的权限进行控制,需要哪些模块,不需要哪些模块,非常方便.
4.模块和反射
模块不能通过反射访问私有属性比如:
package hellomod.test; public class ReflectTest { private Integer name; public ReflectTest(Integer name) { super(); this.name = name; } }
我在另一个模块通过反射访问name,会报错
ReflectTest reflectTest = new ReflectTest(123); Field field = reflectTest.getClass().getDeclaredField("name"); System.out.println(field.getInt(reflectTest));
解决: 在要访问的模块中添加open关键词即可
open module hellomod.test{
exports hellomod.test;
}
如图 我们在module 前面添加 open即可
或者添加exports和opens关键词
module hellomod.test{
exports hellomod.test;
opens hellomod.test;
}
即可开放反射访问权限
5.自动模块和不具名模块
自动模块: 就是把jar文件放到模块路径上的模块. 为了改造以前的方式成模块,jar文件直接可以放到模块路径上成为一个新的模块
所有包都导出,包含其他所有模块
不具名模块: 不在模块路径中的类组成的模块.
可以访问其他模块,但是不能被其他模块访问
6.依赖的传递和静态模块
如果想要传递依赖,使用 transitive关键字即可
module v2ch09.exportedpkg {
requires transitive com.horstmann.greet;
requires hellomod.test;
}
这样,别的模块引入v2ch09.exportedpkg这个模块以后,也会自动引入com.horstmann.greet这个模块
静态模块是 requires static,声明一个模块必须在编译时出现,运行时可选,也就是写代码的时候可以存在,但是运行以后能不能用就另外当回事了.
7.限定导出和开放
to关键词可以做到让模块给指定的模块开放,比如:
module hellomod.test{
exports hellomod.test;
opens hellomod.test to com.horstmann.greet;
}
hellomod.test,只有com.horstmann.greet模块才可以使用反射,或者在exports后面加入也可以.
8.服务加载 ServiceLoader
ServiceLoader提供了一个机制,用于将服务和实现匹配,在模块中,可以用 provices和uses实现.
比如:
一个接口
public interface GreeterService { void hello(); }
有两个实现类
public class FrenchGreeter implements GreeterService{ @Override public void hello() { System.out.println("FrenchGreeter Hello"); } } public class GermanGreeterFactory implements GreeterService { @Override public void hello() { System.out.println("GermanGreeter Hello"); } }
module com.horstmann.greetsvc {
exports com.horstmann.greetsvc;
provides com.horstmann.greetsvc.GreeterService with
com.horstmann.greetsvc.internal.FrenchGreeter,
com.horstmann.greetsvc.internal.GermanGreeterFactory;
}
在module中我们可以这样声明, provides 提供接口,with后面跟着实现类,
在另一个模块中我们可以这样使用
requires com.horstmann.greetsvc;
uses com.horstmann.greetsvc.GreeterService;
代码中这样写
ServiceLoader<GreeterService> greeterLoader = ServiceLoader.load(GreeterService.class); GreeterService user = null; for(GreeterService greetService : greeterLoader) { user = greetService; user.hello(); }
我们就通过类似于 spring 方式一样,或者了GreeterService所有实现类,一个遍历直接获取了所有的实现类.
9. 模块化工具
jdeps jlink等,需要时在看吧.