equinox java
Eclipse Equinox项目为开发各种OSGi规范的实现提供了一个社区。 在Equinox和OSGi规范的中心是OSGi框架提供的Java tm动态模块系统。 许多其他Eclipse项目使用此模块系统来模块化其代码并提供可扩展性。 一个示例项目是Eclipse项目,该项目使用Equinox为开发Eclipse插件提供可扩展的平台。
随着Java 9发行版的发布,Java平台模块系统(JPMS)即将面世。 JPMS将最终模块化JVM提供的类库。 另外,开发人员可以使用JPMS来模块化应用程序。 这使开发人员可以将其应用程序拆分为模块。 然后,这些模块可以指定它们需要哪些其他模块,以及导出哪些软件包以供其他模块使用。
OSGi规范已经为Java应用程序提供了很长一段时间的模块系统,这也允许开发人员将其应用程序模块化为模块(也称为捆绑包)。 使用OSGi,开发人员创建了许多模块化应用程序,这些应用程序也可以通过安装第三方提供的更多捆绑软件进行扩展。
发行JPMS后,开发人员可以开始为JPMS交付自己的Java模块。 当开发人员想要使用Java模块来编写在使用OSGi模块系统构建的容器上运行的应用程序时,会发生什么? 容器是否能够以JPMS模块所需的方式提供和访问API? 本新闻稿关注与Eclipse项目类似的这种情况。 在深入探讨问题之前,我们首先应该探讨JPMS和“ 层”的概念。 请注意,在撰写本文时,后面的细节是JPMS中的工作方式。 JPMS仍在开发过程中,其中一些细节可能会更改。
JPMS层和模块
JPMS中的一层是一组静态的已解析模块。 除没有父级的空层外,每个层都有一个父级层。 层是分层的,不能有循环。 一层为JVM提供了一个图形,该图形确定了在类加载期间如何定位类。 创建图层后,该图层内的任何模块都无法更改。 这允许在创建图层时将类加载图锁定。 一层中的模块可能需要父层中提供的任何模块。 这包括层次结构中的所有父级直到空层。 为了更新模块,必须丢弃并重新创建其中包含模块的完整层,以便为该层提供新的分辨率图。 如果需要更新层次结构中某个层中的任何模块,则必须拆除该层以及该层的所有子级并重新创建。 如果需要在启动层中加载JVM提供的另一个模块,则必须重新启动完整的JVM,以便JVM可以重新创建启动层。
这提供了稳定且可预测的类加载行为,但对于使用OSGi模块系统构建的容器却造成了问题。 OSGi模块系统更加动态。 OSGi中的模块(捆绑包)没有放置在分层层中,而分层层是按有序阶段(如JPMS层)解析的。 在OSGi中,彼此不依赖的捆绑包可以彼此独立地解析。 不仅如此,还可以安装新的捆绑软件,并且可以更新或卸载现有的捆绑软件。 所有这些都不会破坏框架或影响框架中现有的捆绑软件,这些捆绑软件不依赖于其他捆绑软件的更新,安装或卸载。
建立在动态模块系统上的容器如何提供一个JPMS层,该层可以用作另一个包含JPMS模块的层的父级? JPMS中的模块只能从从其自己的层或父级层次结构之一中的模块导出的包中加载类。 如果容器提供由OSGi捆绑包导出的API,则必须以某种方式在JPMS层中表示由JPMS模块组成的应用程序可以使用的任何API。 下图说明了此方案的可能层:
引导层包含JPMS模块,这些模块是在JVM启动时配置的。 在此图中,框架启动器也已迁移到Java 9,以使其为用于加载框架实现的类加载器创建一个Layer 。 该层配置一个名为system.bundle的模块。 这允许将Framework实现的所有类与system.bundle模块关联。 接下来是捆绑层。 该层配置为将每个捆绑软件类加载器映射到表示捆绑软件的命名模块。 最后,我们有一个模块层,它使用Java 9 for JPMS的所有内置模块类加载器。
OSGi JPMS层
一个github项目( OSGi-JPMS层 )研究了这种方法。 该项目的一个目标是通过仅使用OSGi指定的API不需要对OSGi框架实现进行任何修改。 此方法对JPMS模块使用自底向上策略。 考虑到这一点,首先需要修改OSGi Framework启动器以创建system.bundle模块。
system.bundle模块
在OSGi中,系统捆绑包将OSGi Framework实现表示为捆绑包。 在OSGi层中,每个捆绑包应由一个命名模块表示。 这包括名为system.bundle的捆绑包。 没有这些,所有实现OSGi框架本身的类最终都将与未命名模块相关联。 未命名的模块在JPMS中有很多限制,但是对OSGi JPMS层影响最大的一个事实是, 未命名的模块不能被JPMS中的其他模块所依赖。
因此,框架启动器需要创建一个可以包含system.bundle模块的图层。 有关创建system.bundle层所需的详细信息,请参阅此处对Equinox启动器所做的修改。
捆绑层
捆绑层实现发现所有已解析的主机捆绑布线 ,并将它们映射到命名模块。 JPMS模块的捆绑接线中使用了以下信息:
模块名称,版本和导出的映射相当容易理解。 但是,不需要导出私有软件包,也不需要将OSGi依赖项转换为模块。 需要这两个映射才能解决运行时JPMS强制执行的某些规则。
必须导出所有专用程序包,以解决JPMS不允许导出另一个模块的类的事实,除非导出该程序包。 最近,JMPS强制进行深度反射检查,仅限于导出为private的软件包。 反射是诸如Eclipse扩展注册表和OSGi声明服务之类的容器使用的重要工具。 为了维护OSGi中的现有行为,必须将捆绑包中包含的所有软件包导出为捆绑包层中的私有包。
OSGi依赖项已映射到模块需求,因此,捆绑类加载程序可以在OSGi捆绑解析期间读取它们连接的其他模块。 JPMS在运行时强制执行读取访问,并且将阻止模块从其没有读取访问权限的另一个模块执行代码。
私有导出和OSGi依赖关系的这种映射确实将JPMS施加了一些限制到OSGi框架上:
- JPMS不允许循环。 创建捆绑图层时,代表OSGi分辨率的周期将导致错误。
- JPMS不允许拆分软件包。 表示OSGi中允许的拆分程序包将在创建捆绑程序层时导致错误。 必须从JPMS模块导出OSGi中所有私有软件包的事实,这使得拆分软件包的可能性更大。
- JPMS层具有静态分辨率。 OSGi具有动态软件包解析度,在创建捆绑软件层之前无法得知。
- 在创建捆绑包层时,必须热切地发现专用软件包。 私人包裹信息并非总是预先知道的。 预先发现所有私有软件包可能会花费很多。
OSGi捆绑包动力学
捆绑软件层代表框架中一组静态的已解析OSGi捆绑软件。 但是OSGi框架中的捆绑包不是静态的。 可以卸载,更新,重新解析它们,并可以安装新的捆绑软件。 如何在JPMS层中表示这种动态性质? OSGi捆绑层使用的方法是创建层的线性图,其中最小的子层代表捆绑的当前状态。 看起来像这样:
此方案从在bundle层1中解析bundle.a和bundle.b开始。然后,创建模块层1来解析jpms.a和jpms.b模块。 之后bundle.b更新并安装bundle.c和bundle.b是为了冲洗掉旧的内容和类加载器刷新。 这使束层1留有“死” bundle.b模块,这也使模块层1过时。 现在必须丢弃模块层1,并且必须为jpms.a和jpms.b模块创建模块层2。 为此,将创建一个新的捆绑软件图层,该图层代表当前已解析的捆绑软件集。
捆绑层1无法丢弃,因为它仍然具有至少一个有效的模块bundle.a 。 bundle.a模块不能在新的层中表示,因为可能已经从bundle.a中包含的包中装入了类 。 代替丢弃捆绑层1,而是创建一个新的捆绑层2,该捆绑层将捆绑层1作为其父级。 捆绑层2将包含所有尚未在父层中表示的模块的新版本。 这使新的bundle.b可以在捆绑程序层1中屏蔽 “已失效”的bundle.b模块。唯一不能被子层屏蔽的JPMS模块是java.base模块。 但是这种方法存在很大的问题。
从JPMS层丢弃的模块将固定在内存中,直到丢弃整个层。 最终会导致类加载器泄漏,因为过时的捆绑类加载器无法正确释放。 它还会导致完全卸载捆绑软件的问题。 这些捆绑包的“停滞”模块将继续可用,因为没有任何东西使它们从子层中消失。 可以创建一个空模块,其名称相同,不导出任何内容,但仍允许最上面的模块在不应该使用的时候进行解析。
该方法的代码当前位于分支tjwatson / moduleClassLoader中的OSGi-JPMS层 GitHub项目中。
结论
这种方法可以将解析后的OSGi捆绑包的静态集合作为JPMS模块相当准确地表示。 但是,在将其视为真正可行的解决方案之前,还需要解决一些问题。 可以确定这些是JPMS今后的永久限制。 但是JPMS有一些调整,可能会使该方法接近完整的解决方案。 JPMS规范邮件列表中目前正在讨论其中一些问题。
- #ReflectiveAccessToNonExportedTypes问题在此线程中进行了讨论。 不幸的是,当前的建议仍然要求所有私有软件包都必须在JPMS层中导出。
- 通过此线程添加了能够控制问题#ReadabilityAddedByLayerCreator的可读性。
- 在该线程中为#NonHierarchicalLayers提出了一个建议。
如果在JPMS中解决了所有这三个问题,则可以在束线和JPMS层/模块之间创建一对一的映射。 根据顶层JPMS层的要求,可以使用一个或多个捆绑层作为其父层来创建它。 随着已解决的捆绑包的动态集在OSGi框架中发生变化,这将允许丢弃单独的捆绑包层。
这篇文章最初发表于2016年 10 月的Eclipse Newsletter:Discover Eclipse Runtimes
有关更多信息和文章,请查阅Eclipse Newsletter 。
翻译自: https://jaxenter.com/eclipse-equinox-java-modules-way-130126.html
equinox java