自己网站做优化的有权利卖么,wordpress插件版本回退,咨询网站建设,深圳企业网站制作流程Jigsaw项目将把模块化引入Java平台#xff0c;根据原始计划#xff0c;它将在12月10日完成功能。 所以我们在这里#xff0c;但是拼图在哪里#xff1f; 在过去的六个月中肯定发生了很多事情#xff1a; 原型问世 #xff0c;内部API的迫在眉睫的删除引起了很大的骚动 根据原始计划它将在12月10日完成功能。 所以我们在这里但是拼图在哪里 在过去的六个月中肯定发生了很多事情 原型问世 内部API的迫在眉睫的删除引起了很大的骚动 邮件列表中充斥着有关项目设计决策的重要讨论 而JavaOne看到了一系列很棒的介绍性演讲 。拼图团队。 然后Java 9因拼图而延迟了半年 。 但是让我们暂时忽略所有这些仅关注代码。 在本文中我们将使用一个现有的演示应用程序并将其与Java 9进行模块化。如果要继续学习请转到GitHub 在该处可以找到所有代码。 设置说明对于使脚本与Java 9一起运行很重要。为简便起见我从本文的所有程序包模块和文件夹名称中删除了前缀org.codefx.demo 。 拼图之前的应用 即使我竭尽全力不理会整个圣诞节但让演示程序秉承本季的精神似乎是审慎的做法。 因此它为出现日历建模 有一个日历其中包含24个日历表。 每张纸都知道该月的某天并包含一个惊喜。 即将到圣诞节的死亡行军是通过在控制台上打印床单以及由此带来的惊喜来象征的。 当然需要首先创建日历。 它可以自己做到这一点但它需要一种创造惊喜的方法。 为此它得到了一个惊喜工厂清单。 main方法如下所示 public static void main(String[] args) {ListSurpriseFactory surpriseFactories Arrays.asList(new ChocolateFactory(),new QuoteFactory());Calendar calendar Calendar.createWithSurprises(surpriseFactories);System.out.println(calendar.asText());
} 该项目的初始状态绝不是拼图之前最好的。 恰恰相反这是一个简单的起点。 它由一个包含所有必需类型的单个模块从抽象意义上讲不是Jigsaw解释组成 “惊喜API” – Surprise和SurpriseFactory 均为接口 “日历API” – Calendar和CalendarSheet用于创建日历 惊喜–几个Surprise和SurpriseFactory实现 Main –连接并运行整个过程。 编译和运行非常简单Java 8的命令 # compile
javac -d classes/advent ${source files}
# package
jar -cfm jars/advent.jar ${manifest and compiled class files}
# run
java -jar jars/advent.jar进入拼图土地 下一步虽小但很重要。 它不会更改代码或其组织只会将其移至Jigsaw模块中。 模组 那么什么是模块 引用强烈推荐的模块系统状态 模块是命名的自描述的代码和数据集合。 它的代码被组织为一组包含类型即Java类和接口的软件包。 其数据包括资源和其他种类的静态信息。 为了控制其代码如何引用其他模块中的类型模块声明要编译和运行它需要哪些其他模块。 为了控制其他模块中的代码如何引用其包中的类型模块声明了要导出的包中的哪个。 因此与JAR相比模块具有JVM可以识别的名称声明其依赖于其他模块并定义哪些包是其公共API的一部分。 名称 模块的名称可以是任意的。 但是为了确保唯一性建议坚持使用包的反向URL命名模式。 因此虽然这不是必需的但通常意味着模块名称是它包含的软件包的前缀。 依存关系 一个模块列出了要编译和运行的其他模块。 对于应用程序和库模块而言这都是正确的但对于JDK本身中的模块而言这是正确的它被分成了大约80个请使用java -listmods 。 再次从设计概述中 当一个模块直接依赖于模块图中的另一个模块时第一个模块中的代码将能够引用第二个模块中的类型。 因此我们说第一模块读取第二模块或者等效地第二模块可被第一模块读取 。 […] 模块系统确保每个依赖关系都由另一个模块准确地满足没有两个模块互相读取每个模块最多读取一个定义给定程序包的模块并且定义同名程序包的模块不会互相干扰。 当违反任何一个属性时模块系统将拒绝编译或启动代码。 这是对脆弱类路径的巨大改进在脆弱类路径中例如丢失的JAR仅在运行时才发现从而使应用程序崩溃。 还需要指出的是只有模块直接依赖于另一个模块才能访问另一个模块的类型。 因此如果A依赖于B 而B依赖于C 那么除非明确要求A 否则A将无法访问C。 出口产品 一个模块列出了它导出的软件包。 这些包中的公共类型只能从模块外部访问。 这意味着public不再是真正的公众。 非导出包中的公共类型与导出包中的非公共类型一样对外界隐藏。 它比当今的私有包类型更加隐藏因为模块系统甚至不允许反射访问它们。 由于拼图是当前实现的命令行标志是解决此问题的唯一方法。 实作 为了能够创建模块项目需要在其根源目录中包含module-info.java module advent {// no imports or exports
} 等等我不是说我们也必须声明对JDK模块的依赖吗 那么为什么我们在这里没有提到什么呢 所有Java代码都需要Object 并且该类以及演示使用的其他少数几个类也是模块java.base一部分。 因此实际上每个 Java模块都依赖于java.base 这导致Jigsaw团队决定自动要求它。 因此我们不必明确提及它。 最大的变化是要编译和运行的脚本Java 9的命令 # compile (include module-info.java)
javac -d classes/advent ${source files}
# package (add module-info.class and specify main class)
jar -c \--filemods/advent.jar \--main-classadvent.Main \${compiled class files}
# run (specify a module path and simply name to module to run)
java -mp mods -m advent 我们可以看到编译几乎相同–我们只需要在类列表中包括新的module-info.java 。 jar命令将创建所谓的模块化JAR即包含模块的JAR。 与之前不同我们不再需要任何清单而是可以直接指定主类。 注意如何在目录mods创建JAR。 完全不同的是启动应用程序的方式。 这样做的目的是告诉Java在哪里可以找到应用程序模块使用-mp mods 这称为模块路径 以及我们想启动哪个模块使用-m advent 。 分成模块 现在是时候真正了解Jigsaw并将其拆分为单独的模块了。 虚构理由 “惊喜API”即Surprise和SurpriseFactory取得了巨大的成功我们希望将其与整体分离。 创造惊喜的工厂非常活跃。 这里要做很多工作它们经常更改并且使用的工厂因版本而异。 因此我们想隔离它们。 同时我们计划创建一个大型的圣诞节应用程序日历仅是其中的一部分。 因此我们也希望为此提供一个单独的模块。 我们最终得到以下模块 惊喜 – Surprise and SurpriseFactory 日历 –日历使用Surprise API 工厂 – SurpriseFactory实现 main –原来的应用程序现在已经镂空到Main类 通过查看它们之间的依赖关系我们可以发现惊喜并不取决于其他模块。 日历和工厂都使用它的类型因此必须依赖它。 最后 main使用工厂来创建日历因此它依赖于两者。 实作 第一步是重新组织源代码。 我们将遵循官方快速入门指南建议的目录结构并将所有模块放在src的自己的文件夹中 src- advent.calendar: the calendar module- org ...module-info.java- advent.factories: the factories module- org ...module-info.java- advent.surprise: the surprise module- org ...module-info.java- advent: the main module- org ...module-info.java
.gitignore
compileAndRun.sh
LICENSE
README 为了保持可读性我删节了org下面的文件夹。 缺少的是软件包以及每个模块的最终源文件。 完整地在GitHub上查看。 现在让我们看看这些模块信息必须包含什么以及如何编译和运行应用程序。 没有必要的条款因为Surprise没有依赖性。 除了java.base 它始终是隐式必需的。它导出包advent.surprise因为它包含两个类Surprise和SurpriseFactory 。 因此module-info.java如下所示 module advent.surprise {// requires no other modules// publicly accessible packagesexports advent.surprise;
} 编译和打包与上一节非常相似。 实际上这甚至更容易因为意外事件不包含任何主要类别 # compile
javac -d classes/advent.surprise ${source files}
# package
jar -c --filemods/advent.surprise.jar ${compiled class files} 日历使用来自Surprise API的类型因此模块必须依赖Surprise 。 向模块添加requires advent.surprise即可实现。 该模块的API由Calendar类组成。 为了使其可公开访问必须导出包含软件包advent.calendar 。 请注意同一包私有的CalendarSheet在模块外部将不可见。 但有一个附加的扭曲我们刚刚作出Calendar.createWithSurprises( ListSurpriseFactory )公布从惊喜模块暴露类型。 因此除非读取日历的模块也需要惊讶 否则Jigsaw将阻止它们访问这些类型这将导致编译和运行时错误。 将require子句标记为public可解决此问题。 有了它任何依赖日历的模块也会让人吃惊 。 这称为隐式可读性 。 最终的模块信息如下所示 module advent.calendar {// required modulesrequires public advent.surprise;// publicly accessible packagesexports advent.calendar;
} 编译几乎像以前一样但是当然必须在此反映对惊奇的依赖。 为此将编译器指向目录mods就足够了因为它包含所需的模块 # compile (point to folder with required modules)
javac -mp mods \-d classes/advent.calendar \${source files}
# package
jar -c \--filemods/advent.calendar.jar \${compiled class files} 该工厂实现SurpriseFactory所以这个模块必须依靠惊喜 。 并且由于它们从已发布的方法返回Surprise实例因此与上述相同的思路导致了requires public子句的出现。 可以在包advent.factories找到工厂因此必须将其导出。 请注意在另一个模块中找到的公共类AbstractSurpriseFactory在此模块外部无法访问。 这样我们得到 module advent.factories {// required modulesrequires public advent.surprise;// publicly accessible packagesexports advent.factories;
} 编译和打包类似于日历 。 我们的应用程序需要日历和工厂这两个模块进行编译和运行。 它没有要导出的API。 module advent {// required modulesrequires advent.calendar;requires advent.factories;// no exports
} 编译和打包与上一节的单个模块相似不同之处在于编译器需要知道在哪里寻找所需的模块 #compile
javac -mp mods \-d classes/advent \${source files}
# package
jar -c \--filemods/advent.jar \--main-classadvent.Main \${compiled class files}
# run
java -mp mods -m advent服务 拼图通过实现服务定位器模式实现松散耦合在该模式中 模块系统本身充当定位器。 让我们看看情况如何 。 虚构理由 最近有人读了一篇关于冷松耦合的博客文章。 然后她从上面看我们的代码抱怨主机和工厂之间的紧密关系。 主为什么还要知道工厂 因为… public static void main(String[] args) {ListSurpriseFactory surpriseFactories Arrays.asList(new ChocolateFactory(),new QuoteFactory());Calendar calendar Calendar.createWithSurprises(surpriseFactories);System.out.println(calendar.asText());
} 真 只是为了实例化完美抽象的某些实现 SurpriseFactory 而且我们知道她是对的。 让其他人为我们提供实现将消除直接依赖。 更好的是如果说中间人能够在模块路径上找到所有实现则可以通过在启动之前添加或删除模块来轻松配置日历的惊喜。 拼图确实可以做到这一点。 我们可以有一个模块来指定它提供接口的实现。 另一个模块可以表示它使用所述接口并使用ServiceLocator查找所有实现。 我们利用这个机会将工厂分割成巧克力然后报价并最终得到以下模块和依赖项 惊喜 – Surprise and SurpriseFactory 日历 –日历使用Surprise API 巧克力 – ChocolateFactory即服务 quote – QuoteFactory即服务 主要 –应用程序 不再需要单个工厂 实作 第一步是重新组织源代码。 之前的唯一变化是src/advent.factories被src/advent.factory.chocolate和src/advent.factory.quote 。 让我们看一下各个模块。 两者都没有改变。 除某些名称外两个模块都是相同的。 让我们看一下巧克力因为它更美味。 和工厂以前一样该模块requires public 惊喜模块。 更有趣的是其出口。 它提供了SurpriseFactory的实现即ChocolateFactory 其指定如下 provides advent.surprise.SurpriseFactorywith advent.factory.chocolate.ChocolateFactory; 由于此类是其公共API的全部因此不需要导出其他任何内容。 因此没有其他出口条款是必要的。 我们最终得到 module advent.factory.chocolate {// list the required modulesrequires public advent.surprise;// specify which class provides which serviceprovides advent.surprise.SurpriseFactorywith advent.factory.chocolate.ChocolateFactory;
} 编译和打包很简单 javac -mp mods \-d classes/advent.factory.chocolate \${source files}
jar -c \--file mods/advent.factory.chocolate.jar \${compiled class files} 关于main的最有趣的部分是它如何使用ServiceLocator查找SurpriseFactory的实现。 从其主要方法 List surpriseFactories new ArrayList();
ServiceLoader.load(SurpriseFactory.class).forEach(surpriseFactories::add); 我们的应用程序现在仅需要日历但必须指定它使用SurpriseFactory 。 它没有要导出的API。 module advent {// list the required modulesrequires advent.calendar;// list the used servicesuses advent.surprise.SurpriseFactory;// exports no functionality
} 编译和执行与以前一样。 我们确实可以通过简单地从模块路径中删除工厂模块之一来更改日历最终将包含的惊喜。 整齐 摘要 就是这样了。 我们已经看到了如何将单片应用程序移动到单个模块中以及如何将其拆分为多个模块。 我们甚至使用服务定位器将我们的应用程序与服务的具体实现分离开来。 所有这些都在GitHub上因此请查看更多代码 但是还有更多要讨论的 拼图带来了一些不兼容问题但也解决了许多不兼容问题。 而且我们还没有讨论反射如何与模块系统交互以及如何迁移外部依赖项。 如果您对这些主题感兴趣请在我的博客上观看Jigsaw标签 因为在接下来的几个月中我一定会写关于它们的。 翻译自: https://www.javacodegeeks.com/2015/12/project-jigsaw-hands-guide.html