module是用来组织packages,经过模块名称(module’s name)来隔离不一样模块之间包的可读性。所以是在Java的访问限制机制public/private/protected上加了一层,先有模块的可读性才有访问性可言。同时jlink工具提供了提取程序最小运行时的支持。
java
模块化机制给Java语言带来一些新的关键字以下:bash
聪明的你可能会想起:在一个成熟的系统引入新的关键字,会不会对已有代码命名形成冲突。答案是:不会。由于这些关键字的使用限定在模块定义文件module-info.java,你在正常的Java代码中仍是可使用这些关键字做为标示符。
下面先稍微简单介绍下上面关键字的做用:ide
exports和requires是一对儿,前者用于导出模块的某些包,后者则是导入须要引入的外部模块的包。模块化
provides/uses/with则是服务提供者机制下的用到的关键字,这个后文有讲解。工具
transitive顾名思义就是指的可传递性,主要用于多个模块串行依赖用于简化书写requires语句的。ui
to主要是和exports组合,用于将模块的包导出到特定模块,成为其专属女佣。this
open/opens主要是用于将模块开放给其余全部模块,可是要注意编译期和运行期的区别。其具体机制后门也会详述。idea
好了,模块的基本概念就到这里了。聪明的你更指望的是一个能运行的实例吧,那咱们下面就开始从代码的角度去使用咱们的模块化机制咯。spa
下面咱们将定义三个模块,这里仍是沿用商品和订单的栗子。咱们定义的三个模块组织以下:命令行
这里咱们定义三个模块:goods/order/pojo,其依赖关系以下:
goods->order->pojo
接下来咱们依次创建好代码目录和 Java文件。固然你也能够手动建立这些目录和代码。
咱们先定义两个实体类Goods.java和Order.java:
package pojo;
import java.util.List;
public class Goods {
private String goodsName;
private double price;
private List<Order> orderList;
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public List<Order> getOrderList() {
return orderList;
}
public void setOrderList(List<Order> orderList) {
this.orderList = orderList;
}
@Override
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", orderList=" + orderList +
'}';
}
}
package pojo;
import java.time.LocalDateTime;
public class Order {
private LocalDateTime createTime;
private LocalDateTime finishTime;
private String orderName;
private String orderUser;
public Order(String orderName) {
this.orderName = orderName;
this.createTime = LocalDateTime.now();
this.finishTime = LocalDateTime.now().plusDays(2);
this.orderUser = "gxf";
}
public LocalDateTime getCreateTime() {
return createTime;
}
public void setCreateTime(LocalDateTime createTime) {
this.createTime = createTime;
}
public LocalDateTime getFinishTime() {
return finishTime;
}
public void setFinishTime(LocalDateTime finishTime) {
this.finishTime = finishTime;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public String getOrderUser() {
return orderUser;
}
public void setOrderUser(String orderUser) {
this.orderUser = orderUser;
}
@Override
public String toString() {
return "Order{" +
"createTime=" + createTime +
", finishTime=" + finishTime +
", orderUser='" + orderUser + '\'' +
'}';
}
}复制代码
接下来在模块的根目录建立module-info.java(注意模块声明文件必须在模块源代码文件的根目录):
module pojo {
exports pojo;
}复制代码
至此咱们定义了名为pojo的模块,而且导出pojo这个包以供其余模块使用。
这里咱们定义一个OrderService类提供商品订单查询方法,其代码以下:
package order;
import pojo.Order;
import java.util.List;
public class OrderService {
public List<Order> queryOrdersByGoodsName(String goodsName) {
return List.of(new Order("oder1"),new Order("oder2")
,new Order("oder3"),new Order("oder4"),new Order("oder5"));
}
}
复制代码
queryOrdersByGoodsName方法构造订单对象列表,注意这里使用Java10集合新的工厂方法来生成的List。
order模块依赖pojo模块,所以其module-info.java定义以下:
module order{
exports order;
requires pojo;
}复制代码
咱们看到该模块依赖pojo同时导出order包,觉得下面的goods模块依赖order。
该模块定义GoodsService类,用于查询商品信息,其代码以下:
package goods;
import order.OrderService;
import pojo.Goods;
public class GoodsService {
private OrderService orderService = new OrderService();
Goods queryGoodsInfoByName(String goodsName) {
Goods goods = new Goods();
goods.setGoodsName(goodsName);
goods.setOrderList(orderService.queryOrdersByGoodsName(goodsName));
return goods;
}
public static void main(String[] args) {
String module = "test",exports = "test",with="with";
System.out.println(new GoodsService().queryGoodsInfoByName("test"));
}
}
复制代码
接下来也要定义其模块声明:
module goods{
requires order;
requires pojo;
}复制代码
由于暂时没有其余模块依赖goods,因此模块定义里没有声明其导出的包。
至此咱们的三个模块已经创建完成。
编译和运行您能够借助IDE工具,可是为了更透彻的理解模块的定义,咱们先采用javac命令来编译和运行咱们的模块。
按照模块的依赖顺序,咱们依次编译pojo->order->goods模块。
咱们使用javac进行编译,编译命令以下:
javac -verbose --module-path target -d target\pojo pojo\src\*.java pojo\src\pojo\*.java
--module-path指定本次编译依赖的外部模块的搜索路径,由于pojo模块没有外部依赖,这个参数在此其实能够忽略。
-d指定编译目标文件存放的目录
-verbose打印详细日志便于咱们观察编译的具体过程
执行此命令控制台打印信息系以下:
D:\code\mods>javac -verbose --module-path target -d target\pojo pojo\src\*.java pojo\src\pojo\*.java
[语法分析开始时间 SimpleFileObject[D:\code\mods\pojo\src\module-info.java]] [语法分析已完成, 用时 23 毫秒] [语法分析开始时间 SimpleFileObject[D:\code\mods\pojo\src\pojo\Goods.java]] [语法分析已完成, 用时 9 毫秒] [语法分析开始时间 SimpleFileObject[D:\code\mods\pojo\src\pojo\Order.java]] [语法分析已完成, 用时 2 毫秒] [正在加载/modules/java.base/module-info.class] [正在加载/modules/java.base/java/util/List.class] [正在加载/modules/java.base/java/lang/Object.class] [正在加载/modules/java.base/java/lang/String.class] [正在加载/modules/java.base/java/time/LocalDateTime.class] [正在加载/modules/java.base/java/lang/Deprecated.class] [正在加载/modules/java.base/java/lang/Override.class] [正在加载/modules/java.base/java/lang/annotation/Annotation.class] [正在加载/modules/java.base/java/lang/annotation/Retention.class] [正在加载/modules/java.base/java/lang/annotation/RetentionPolicy.class] [正在加载/modules/java.base/java/lang/annotation/Target.class] [正在加载/modules/java.base/java/lang/annotation/ElementType.class] [正在检查<匿名>] [已写入DirectoryFileObject[target\pojo:module-info.class]] [正在检查pojo.Goods] [正在加载/modules/java.base/java/io/Serializable.class] [正在加载/modules/java.base/java/lang/AutoCloseable.class] [正在加载/modules/java.base/java/lang/Byte.class] [正在加载/modules/java.base/java/lang/Character.class] [正在加载/modules/java.base/java/lang/Short.class] [正在加载/modules/java.base/java/lang/Long.class] [正在加载/modules/java.base/java/lang/Float.class] [正在加载/modules/java.base/java/lang/Integer.class] [正在加载/modules/java.base/java/lang/Double.class] [正在加载/modules/java.base/java/lang/Boolean.class] [正在加载/modules/java.base/java/lang/Void.class] [正在加载/modules/java.base/java/lang/invoke/StringConcatFactory.class] [正在加载/modules/java.base/java/lang/invoke/MethodHandles.class] [正在加载/modules/java.base/java/lang/invoke/MethodHandles$Lookup.class] [正在加载/modules/java.base/java/lang/invoke/MethodType.class] [正在加载/modules/java.base/java/lang/invoke/CallSite.class] [已写入DirectoryFileObject[target\pojo:pojo/Goods.class]] [正在检查pojo.Order] [正在加载/modules/java.base/java/time/temporal/Temporal.class] [正在加载/modules/java.base/java/time/temporal/TemporalAccessor.class] [正在加载/modules/java.base/java/time/temporal/TemporalAdjuster.class] [正在加载/modules/java.base/java/time/chrono/ChronoLocalDateTime.class] [正在加载/modules/java.base/java/lang/Comparable.class] [已写入DirectoryFileObject[target\pojo:pojo/Order.class]] [共 485 毫秒]
上面的输出信息代表:虽然咱们的pojo没有显示声明requires哪些模块,可是系统默认导入了java.base模块。也就是说咱们定义的模块都隐士依赖java.base模块,这仅仅是为了导入常见的一些Java类库。其余输出信息读者能够自行查看。
相似的执行下边命令便可:
D:\code\mods>javac -verbose --module-path target -d target\order order\src\*.java order\src\order\*.java
[语法分析开始时间 SimpleFileObject[D:\code\mods\order\src\module-info.java]] [语法分析已完成, 用时 34 毫秒] [语法分析开始时间 SimpleFileObject[D:\code\mods\order\src\order\OrderService.java]] [语法分析已完成, 用时 2 毫秒] [正在加载target\pojo\module-info.class] [正在加载/modules/java.base/module-info.class] [正在加载target\pojo\pojo\Order.class] [正在加载/modules/java.base/java/util/List.class] [正在加载/modules/java.base/java/lang/Object.class] [正在加载/modules/java.base/java/lang/String.class] [正在加载/modules/java.base/java/lang/Deprecated.class] [正在加载/modules/java.base/java/lang/annotation/Retention.class] [正在加载/modules/java.base/java/lang/annotation/RetentionPolicy.class] [正在加载/modules/java.base/java/lang/annotation/Target.class] [正在加载/modules/java.base/java/lang/annotation/ElementType.class] [正在检查<匿名>] [已写入DirectoryFileObject[target\order:module-info.class]] [正在检查order.OrderService] [正在加载/modules/java.base/java/io/Serializable.class] [正在加载/modules/java.base/java/lang/AutoCloseable.class] [正在加载/modules/java.base/java/util/Collection.class] [正在加载/modules/java.base/java/lang/Iterable.class] [已写入DirectoryFileObject[target\order:order/OrderService.class]] [共 684 毫秒]
输出信息咱们能够清楚的看到,该模块先加载target\pojo\module-info.class模块而后加载java.base模块。
D:\code\mods>javac -verbose --module-path target -d target\goods goods\src\*.java goods\src\goods\*.java
[语法分析开始时间 SimpleFileObject[D:\code\mods\goods\src\module-info.java]] [语法分析已完成, 用时 32 毫秒] [语法分析开始时间 SimpleFileObject[D:\code\mods\goods\src\goods\GoodsService.java]] [语法分析已完成, 用时 7 毫秒] [正在加载target\order\module-info.class] [正在加载target\pojo\module-info.class] [正在加载/modules/java.base/module-info.class] [正在加载target\order\order\OrderService.class] [正在加载target\pojo\pojo\Goods.class] [正在加载/modules/java.base/java/lang/Object.class] [正在加载/modules/java.base/java/lang/String.class] [正在加载/modules/java.base/java/lang/Deprecated.class] [正在加载/modules/java.base/java/lang/annotation/Retention.class] [正在加载/modules/java.base/java/lang/annotation/RetentionPolicy.class] [正在加载/modules/java.base/java/lang/annotation/Target.class] [正在加载/modules/java.base/java/lang/annotation/ElementType.class] [正在检查<匿名>] [已写入DirectoryFileObject[target\goods:module-info.class]] [正在检查goods.GoodsService] [正在加载/modules/java.base/java/io/Serializable.class] [正在加载/modules/java.base/java/lang/AutoCloseable.class] [正在加载/modules/java.base/java/util/List.class] [正在加载target\pojo\pojo\Order.class] [正在加载/modules/java.base/java/lang/System.class] [正在加载/modules/java.base/java/io/PrintStream.class] [正在加载/modules/java.base/java/lang/Appendable.class] [正在加载/modules/java.base/java/io/Closeable.class] [正在加载/modules/java.base/java/io/FilterOutputStream.class] [正在加载/modules/java.base/java/io/OutputStream.class] [正在加载/modules/java.base/java/io/Flushable.class] [已写入DirectoryFileObject[target\goods:goods/GoodsService.class]] [共 650 毫秒]
至此咱们完成了全部模块的编译,如今咱们来看看编译结果:
咱们的运行入口在goods.GoodsService,运行命令以下:
D:\code\mods>java --module-path target -m goods/goods.GoodsService
Goods{goodsName='test', orderList=[Order{createTime=2018-06-25T14:56:53.541093100, finishTime=2018-06-27T14:56:53.541093100, orderUser='gxf'}, Order{createTime= 2018-06-25T14:56:53.541093100, finishTime=2018-06-27T14:56:53.541093100, orderUser='gxf'}, Order{createTime=2018-06-25T14:56:53.541093100, finishTime=2018-06-27 T14:56:53.542053500, orderUser='gxf'}, Order{createTime=2018-06-25T14:56:53.542053500, finishTime=2018-06-27T14:56:53.542053500, orderUser='gxf'}, Order{createT ime=2018-06-25T14:56:53.542053500, finishTime=2018-06-27T14:56:53.542053500, orderUser='gxf'}]}
--module-path指定模块根目录,也就是咱们编译结果存放的根目录
-m指定程序的入口,其用法是:
-m <module>/<main-class>
所以必须是带模块名而后是主类名。
好了,至此模块的基础知识咱们已经掌握的差很少了。若是你不喜欢命令行,则能够考虑使用idea来进行编译。在idea编译的时候会报错找不到模块,根据提示将依赖模块导入便可。
由于代码量不多,建议你们仍是手动建立一遍,毕竟代码均可以复制粘贴了。本身实践一遍是否是印象更深入呢。
因为篇幅和时间关系,关于模块的其余知识我会另起一篇再进行讲述,但愿你们天天都有进步。