根据 Mark Reinhold 的推特帖子,我将假设 Jigsaw 将成为 Java 9 的一部分。
在阅读 Jigsaw 时,我问自己一个问题:当我使用自定义模块化运行时映像发布我的应用程序时会发生什么,但是第三方模块需要额外的 JRE 模块,这些模块没有随应用程序一起发布,因为它们不是应用程序?
想象一个想要从模块化中受益的应用程序。它提供了一个可以由第三方模块实现的服务接口。应用程序在启动时加载所有提供服务接口实现的第三方模块。在我看来,这是为第三方插件提供公共 API 的一种非常简单的方法,我可以想象自己经常使用它。
现在,还有一个名为的工具jlink,它允许创建一个应用程序的版本,该版本不仅包含应用程序模块,还包含所需的 JRE 模块。这称为自定义模块化运行时映像。很棒的是,该版本仅包含应用程序实际使用的 JRE 模块,这可以防止版本变得非常大。目前,jlink将确定哪些模块必须自己包含在内。但是,开发人员必须明确包含提供服务实现的模块,请参见此处。我认为这对于开发人员不想要求用户安装 JRE 的许多应用程序也非常有用。
当我们尝试在单个应用程序中同时使用两者时会出现问题:自定义模块化运行时映像仅包含应用程序使用的 JRE 模块。但是,插件可能使用应用程序未使用的 JRE 模块,因此这些模块在运行时不可用。因此,该插件将不起作用。
这是我能想到的唯一解决方案,但它远非完美:
将缺少的 JRE 模块包含到第三方插件中。虽然起初这似乎是一个简单的解决方案,但它实际上带来了很多问题。
首先,这需要插件开发人员知道应用程序中包含哪些 JRE 模块。如果这是未知的,它们可能包含应用程序本身已经可用的 JRE 模块,这可能会导致问题。因此,应用程序使用哪些模块成为公共 API 的一部分。我认为这是不可取的,因为它是一个实现细节。此外,它可能会经常更改。
其次,由于可用的 JRE 模块是公共 API 的一部分,因此需要以某种方式指定它们。虽然这可能通过文档起作用,但我认为它应该通过正式代码指定。例如,requires public在应用程序模块中为插件模块应该可用的所有 JRE 模块使用一个子句可能会起作用。这使得这些 JRE 模块可用于插件,因为插件将require成为应用程序模块。
第三,问题出现了是否允许插件使用额外的 JRE 模块。如果不是,则可能应该有一个子句module-info.java来指定当前模块是给定其他模块的插件。例如,不是使用require应用程序模块,而是使用plugs in to或另一种表示法。这将阻止模块需要任何 JRE 模块。但是,这可能行不通,因为插件模块所需的其他第三方模块可能需要额外的 JRE 模块。因此,我认为很难为这样的机制提供支持。
第四,允许插件使用额外的 JRE 模块也很困难。这将要求不同的 JRE 模块在不同的版本中兼容,或者插件开发人员始终将附加的 JRE 模块包含在与应用程序中 JRE 模块的版本兼容的版本中。我不确定 JRE 模块是否应该在不同版本中兼容,但我的假设是它们不应该兼容,因为它会阻止未来的许多变化。
我的一些假设是错误的吗?也许在应用程序和插件中包含一个 JRE 模块就可以了?也许插件中的附加 JRE 模块也不必与应用程序中的 JRE 模块兼容?毕竟,他们可能不会相互交流。
我们应该如何处理这个架构问题?是否有其他具有模块化和部分可发布运行时的语言?他们是如何解决问题的?
请注意,Google guava 或 Apache commons 等常用库可能会出现类似问题。但是,这个问题应该主要是关于使用自定义模块化运行时映像所产生的问题。