关于模块的安全性问题
模块啊,模块。 Java的信天翁。 我经常开玩笑说为Java N + 1安排了模块,其中N在每个发行版中都向前发展。 我完全记得我第一次听说在Devoxx上获得Java模块时,还是在Java 7仍在计划中的时候。我记得我听到了这个公告,并且我所看到的很有意义,我迫不及待地想要获得它们。 我完全同意并仍然同意这样的主张,即模块像包一样属于语言,并且不应将它们委派给第三方外部系统,这些外部系统永远无法达到可以实现的集成级别。通过成为语言的组成部分。 然后,他们将其推向Java 8,再推向Java9。这很遗憾,因为它看起来像是一个经过深思熟虑的模块系统。
同时,Ceylon已经以一种很棒的方式支持模块。 但是为什么我们需要模块? 这里有一些简单的答案:
- 用作比包装更大的容器。 每个人都将Java代码运送到通常被认为是模块的jar中:它们代表一组实现库或程序并具有版本的软件包。
- 为了表达和解决依赖关系:您的模块(jar)将依赖于其他模块(jar),因此我们应该知道它们是什么以及如何找到它们。
- 分发模块:Linux分发版一直在这样做。 在模块具有名称和版本的模块化系统中,您可以按标准层次结构组织它们,然后工具可以使用这些层次结构以标准方式获取这些模块。 有了依赖关系,这些工具也可以下载/上传依赖关系,这意味着分发变得更加简单。
- 在运行时隔离模块。 这是逃避臭名昭著的类路径的一部分:如果在运行时隔离模块,则可以有多个程序同时依赖于同一模块的不同版本。
那么,如果我们在语言中有模块,而不是在语言之外,那为什么会更好呢?
- 它是标准,工具必须支持它。 您可以将其视为不利因素,但实际上,您宁愿未指定Java语言的哪一部分? 您准备好将软件包的实现委派给第三方工具了吗? 使用单一方法来处理模块对用户和实现者都有很大帮助。
- 您摆脱了外部工具,因为突然间
javac
,java
和朋友知道了如何发布,获取和执行模块及其依赖项。 没有更多的管道和低于标准的配件。 - 它与反射集成在一起。 模块在运行时是可见的,完全经过了重组,并且希望也可以动态化,就像类和包一样。
- 依赖项和模块与构建系统分开。 绝对没有充分的理由将两者相互混淆。
这些就是为什么我不能等待Java N + 1拥有模块的原因,我认为它们会很棒。 但是,如果您现在需要模块,则可以使用Ceylon。
锡兰支持语言从一开始就具有以下功能:
- 一个超级小的
ceylon.language
基本模块,这是开始使用Ceylon所需的全部 - 模块化SDK
- 很棒的模块仓库: 牧群
- 在所有工具中都支持模块存储库,无论是命令行还是IDE。 他们知道如何处理依赖关系,如何在本地或远程存储库中获取或发布模块
- 通过IDE对Herd信息库提供了出色的支持,能够搜索模块,具有自动完成功能以及所有功能
- 支持模块化JDK,使用与Jigsaw项目(Java计划的模块化SDK)相同的模块映射
- 甚至与Maven存储库具有互操作性,因此您可以像使用锡兰模块一样使用Maven模块
其他现有的第三方模块系统
正如我提到的,我们支持使用Ceylon的Maven存储库,并且我们也可能会及时支持OSGi。 这些是Java的两个主要的第三方模块系统。 OSGi在应用程序服务器或IDE中使用很多,但大多数Java程序员更喜欢Maven,但很少使用。 Maven是第一个为JVM提供模块化和构建系统的系统。 在此之前,我们有Ant,它仅提供构建系统。 Maven从根本上胜过Ant,因为它支持模块化,这意味着人们不再需要担心如何获得依赖关系。 即使将模块化解决方案自身应用,分发Maven模块也比分发Ant模块变得更加容易。
Maven支持模块化和依赖关系,以便解析和下载它们,但是一旦下载它们,依赖关系就会塞入类路径中,因此就Java编译器或运行器而言,模块化已被删除。 在运行时不支持同一模块的多个版本,也不支持任何形式的依赖关系验证。
未声明的传递依赖问题
我们最近收到了有关Ceylon的错误报告,由于缺少相关性,我们的用户无法使用Ceylon的Maven模块。 由于我们确实使用了Maven提供的依赖关系,因此发现这有点奇怪。 经过检查,看来我们已经被Maven的模块化擦除所打击。 这是您可以使用Maven模块执行的简单示例:
- 您编写了一个使用模块B和C的模块A,但是只声明了对模块B的依赖
- 模块B取决于模块C
- 模块C不依赖任何东西
在Ceylon中,如果您尝试编译模块A,则编译器不会让您,因为您无法依赖C。使用Maven,它就可以工作,因为Maven会获取模块B和C并将它们放在类路径中,这意味着所有隐式传递依赖最终对您的模块可见。 模块化被删除。 这似乎很方便,但是实际上意味着不检查依赖项并且不能信任它们。
因此,我们不能依靠Maven模块正确声明其依赖关系,因此我们不能孤立地运行Maven模块。
未声明的隐式依赖问题
未检查的模块系统还存在一个更微妙的错误:隐式依赖关系。 这是您可以使用Maven进行的操作:
- 模块A使用模块B
- 模块B依赖于模块C并声明它
- 模块B在其公共API中使用模块C中的类型,例如参数类型,方法或字段类型,甚至是超类
这是第一种问题的变体,除了在这种情况下,任何人都不能使用模块B而不直接导入模块C,因为在不了解模块C的类型的情况下不可能使用模块B的类型。
在Ceylon中,如果您尝试编译模块B,则除非您导出模块C依赖项,否则编译器不会允许您进行编译。 这样,当您依赖于模块B时,您也会自动也依赖于模块C,因为您确实需要同时可见这两者才能使用模块B的API。
支持集成模块系统的另一点
如果我们从一开始就在Java中使用适当的模块隔离来构建集成模块系统,那么我们就不会遇到我所描述的问题,因为缺少依赖项在Maven中如此普遍,因为没有工具可以防止您犯这些错误。 。 除非您导入软件包,否则编译器不允许您使用软件包,因此没有理由指望它们不会对模块适用。
我仍然认为Java的模块项目将是一个巨大的飞跃,但是由于Java N + 1仍然不在这里,而且我们想使用大量的Maven模块库,因此我们必须找到一种方法绕过Maven依赖项声明的限制,让您可以在锡兰使用它们。 从自动检测依赖关系到通过字节码分析到将Maven模块存储在“平面类路径”容器中,甚至通过用户可以“修复” Maven依赖项的依赖项覆盖,我们对此有各种想法。 我们仍在评估每个解决方案的过程,但是如果您有其他建议,请随时提出。
翻译自: https://www.javacodegeeks.com/2013/04/about-modules.html
关于模块的安全性问题