在普通java中拆分包

OSGi存在拆分包的问题,​​即相同的包但托管在多个包中。

是否有任何边缘情况,拆分包可能会在普通java(没有OSGi)中造成问题?

只是好奇。

对于OSGi,不同包中的包不同,不管它们的名称如何,因为每个包都使用自己的类加载器。 确保封装包装不是问题,而是一个特征。

所以在普通的Java中,这通常不是问题,直到你开始使用一些使用类加载器的框架。 这通常是组件加载时的情况。

拆分包来自哪里

当使用清单头Require-Bundle (因为我相信,在Eclipse的清单中)会发生拆分包 (在OSGi中)。 Require-Bundle命名用于搜索类的其他包(如果包不是Import ed)。 搜索在捆绑包自己的类路径被搜索之前发生。 这允许从多个 bundle(可能是不同的jar)的导出中加载单个包的类。

OSGi规范(4.1)第3.13节描述了Require-Bundle并且有一长串(意外)使用这个标题的结果(不应该弃用这个标题吗?),其中一部分专门用于拆分包 。 其中一些后果是奇怪的(而且特定于OSGi),但如果您理解一件事,大多数都会被避免:

  • 如果一个 (在一个包中)由多个包提供,那么你就麻烦了。

如果包装件是不相交的,那么一切都应该很好,除了你可能没有在任何地方可见的类,并且如果从拆分包的“错误”部分查看,包可见性成员可能看起来是私有的。

[当然这太简单了 – 可以安装多个版本的软件包 – 但是从应用程序的角度来看,任何时候软件包中的所有类都应该来自单个模块。

‘标准Java’中会发生什么

在标准的Java中,没有花哨的类加载器,你有一个类路径,并且要加载的类的jar(和目录)的搜索顺序是固定的和明确定义的:你得到的就是你得到的。 (但是,我们放弃了可管理的模块化。)

当然,你可以使用拆分包 – 事实上它很常见 – 这表明模块化程度很差。 症状可能是模糊的编译/构建时错误,但在多个类实现的情况下(一个在一个类路径中覆盖其余的),它通常会产生模糊的运行时行为,因为语义略有不同。

如果你很幸运,你最终会看到错误的代码 – 没有意识到 – 并且问自己“但是怎么可能这样做呢?”
如果你运气不好,那么你正在查看正确的代码,并要求完全相同的东西 – 因为其他东西正在产生意想不到的答案。

这与旧的数据库格言并不完全不同:“如果你在两个地方记录同一条信息,很快它将不再相同”。 我们的问题是“很快”通常不会很快。

在jar子上拆分包装可能不是一个好主意。 我建议将jar子里的所有包装密封(在清单的主要部分放置"Sealed: true" )。 密封包装不能在jar子之间分开。

对于OSGi,具有相同包名但具有不同类加载器的类被视为在不同的包中。

如果你在同一个包中有类,有些是在签名的JAR中,而有些则不是,那么你会遇到一个讨厌的运行时错误。

你问的是因为有问题的包是你的,而不是第三方代码吗?

一个简单的例子是将服务和持久层作为单独的OSGi包的Web应用程序。 持久性接口必须由两个bundle共享。

如果我正确地解释了你的问题,那么解决方案是创建一个包含共享接口的密封JAR并使其成为两个包的一部分吗?

我不是故意试图劫持线程。 我要求澄清以及那些可能在OSGi上做得比我更多的人更好的见解。