何时在 OSGi 之类的东西上使用 ServiceLoader

Posted

技术标签:

【中文标题】何时在 OSGi 之类的东西上使用 ServiceLoader【英文标题】:When to use ServiceLoader over something like OSGi 【发布时间】:2010-12-29 22:06:02 【问题描述】:

作为一个对依赖项过敏的人,我什么时候会使用 OSGi 之类的东西,而不是内置的 java 6 http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html(我想让插件 jar 被放入)。

(仅供参考,这是在一个 scala 应用程序中,欢迎任何建议,ServiceLoader 非常接近我想要的)。

【问题讨论】:

【参考方案1】:

正如 seh 所指出的,如果您只对简单的服务发现感兴趣,那么 ServiceLoader 是一种将消费者与提供者分离的轻量级方法。但它不提供任何组合服务的帮助。

例如,假设服务A需要使用服务B。这是一个“服务依赖”......但是如果B不可用,A该怎么办?在 OSGi 中,我们可以安排如果 B 不可用,那么 A 也不可用——假设依赖是强制性的;我们还可以支持可选依赖项。另一方面,在使用 ServiceLoader 时,服务 A 无法控制其可用性,只要包含它的 JAR 在类路径中……因此即使在没有所需的“后端”服务的情况下,它也必须提供其功能。

使用 ServiceLoader 要记住的另一件事是尝试抽象查找机制。发布机制非常好,干净且具有声明性。但是查找(通过 java.util.ServiceLoader)非常丑陋,它被实现为一个类路径扫描器,如果您将代码放入任何不具有全局可见性的环境(例如 OSGi 或 Java EE),它会严重中断。如果您的代码与此纠缠不清,那么您以后将很难在 OSGi 上运行它。最好写一个你可以在时机成熟时替换的抽象。

【讨论】:

您能否详细说明 ServiceLoader 的一个简单抽象,以便以后更容易迁移到 OSGi。我目前有一个框架,它分为 12 或 13 个 jar 文件,它使用核心组件的服务加载器机制来“扫描”类路径上的模块。我希望该框架将来能在 OSGi 中很好地发挥作用,但不依赖于 OSGi。到目前为止,我看不到如何实现对偶性。在使用ServiceLoader机制的时候,甚至有可能半进半出OSGi吗? 最好的抽象是依赖注入。在需要一些服务“Foo”的代码中,不要尝试查找该服务,而只是允许它通过 setFoo() 方法注入。从其他类调用 ServiceLoader 以获取 Foo 的实例并将其注入到需要它的代码中。如果您稍后迁移到 OSGi,只需废弃第二个类并使用声明式服务或蓝图来处理 OSGi 服务的注入。 “全球可见性”是什么意思?在这种情况下,例如在 Java EE 环境中,查找机制如何中断? @du369 这是指应用程序类路径。如果您使用多个类加载器,则服务可能从一个模块到另一个模块不可见,具体取决于您如何设置这些类加载器。【参考方案2】:

如果ServiceLoader 最符合您的需求,则表示您正在通过类路径上的文件来寻找服务发现。这只是 OSGi 提供的一小部分。

OSGi 将允许您在应用程序运行时动态安装捆绑包、广告服务、撤销广告和卸载捆绑包。此外,作为服务的消费者,您可以急切地查找它们——通过过滤谓词查询——并检测提供的服务提供者何时来去。这些包不需要位于类路径上,它们可以以各种形式提供; Jar 文件和“爆炸目录”是我记得的两个。

相比之下,ServiceLoader 只做一件事:它暴露了可发现的工厂。通常你会创建一个工厂风格的接口,它接受一些参数来决定该提供者是否可以提供适当的服务,例如将给定的字符集名称映射到CharsetDecoder。没有正式的协议可用于从此类提供商处获取和发布服务。 OSGi 确实将消费者与服务的绑定和解除绑定正式化。消费者可以在新的提供者上线时收到通知,提供者可以在消费者获取和释放服务实例时收到通知。如果这个生命周期控制对您的服务很重要并且您放弃了 OSGi,那么您必须自己构建它; ServiceLoader 没那么远。

或者,您可以采取更被动、声明性的方法,让其中一个 OSGi 依赖项管理器将您声明的需求与可用的服务提供者相匹配,而不是急切地查找和使用服务。有许多依赖管理器可供选择。 Spring Dynamic Modules 是最有能力的人之一。

OSGi 提供了许多其他“中间件”工具。我不会在这里向您推销它们,因为您的问题主要集中在选择ServiceLoader 会错过什么。

【讨论】:

谢谢 - 总是很难真正了解 OSGi 是什么。不,我真的只需要 ServiceLocator 所拥有的,我很欣赏它是内置的。我只是怀疑,在我认为它一定有病或其他原因之前没有听说过。 我在当前项目中使用ServiceLoader,我发现的唯一挫折是 1) 需要将扩展​​作为 Jar 文件推送到类路径中(我们的应用程序不鼓励 end-用户摆弄类路径),以及 2)相同服务接口的兄弟提供者向消费者公开的未指定顺序。后者使得很难合并“优先级”,例如用户提供的扩展应该比应用程序的基本服务更可取。因此,ServiceLoader 最适合在提供商不会重叠或相互竞争的情况下使用。

以上是关于何时在 OSGi 之类的东西上使用 ServiceLoader的主要内容,如果未能解决你的问题,请参考以下文章

何时使用 OSGi EventAdmin,何时不使用?

OSGI中的service依赖关系管理

如何开始使用 OSGi

OSGi HTTP Bundle - 绑定到两个端口

在Java中拆分String的有效方法

微软有类似的 OSGI 吗?