作为对依赖项过敏的人,我什么时候会使用 OSGi 之类的东西而不是内置的 java 6 http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html(我想要让插件罐子被放入)。
(仅供参考,这是在一个 scala 应用程序中,对任何建议开放,ServiceLoader 非常接近我想要的)。
作为对依赖项过敏的人,我什么时候会使用 OSGi 之类的东西而不是内置的 java 6 http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html(我想要让插件罐子被放入)。
(仅供参考,这是在一个 scala 应用程序中,对任何建议开放,ServiceLoader 非常接近我想要的)。
如果ServiceLoader
最符合您的需求,则表示您正在通过类路径上的文件来寻找服务发现。这只是 OSGi 提供的一小部分。
OSGi 将允许您在应用程序运行时动态安装捆绑包、广告服务、撤销广告和卸载捆绑包。此外,作为服务的消费者,您可以急切地查找它们——通过过滤谓词查询——并检测提供的服务提供者何时来去。这些包不需要位于类路径上,它们可以以各种形式提供;Jar 文件和“爆炸目录”是我记得的两个。
相比之下,ServiceLoader
它只做一件事:它暴露了可发现的工厂。通常你会创建一个工厂风格的接口,它接受一些参数来决定该提供者是否可以提供适当的服务,例如将给定的字符集名称映射到CharsetDecoder
. 没有正式的协议可用于从此类提供商处获取和发布服务。OSGi 确实将消费者与服务的绑定和解除绑定正式化。消费者可以在新的提供者上线时收到通知,提供者可以在消费者获取和释放服务实例时收到通知。如果这个生命周期控制对您的服务很重要并且您放弃了 OSGi,那么您必须自己构建它;ServiceLoader
没那么远。
或者,您可以采取更被动的、声明性的方法,让 OSGi 依赖管理器之一将您声明的需求与可用的服务提供者相匹配,而不是急切地查找和使用服务。有许多依赖管理器可供选择。Spring Dynamic Modules是最有能力的模块之一。
OSGi 提供了许多其他“中间件”工具。我不会尝试在这里向您推销它们,因为您的问题主要集中在您选择ServiceLoader
.
正如 seh 所指出的,如果您只对简单的服务发现感兴趣,那么 ServiceLoader 是一种将消费者与提供者分离的轻量级方法。但它不提供任何组合服务的帮助。
例如,假设服务A需要使用服务B。这是一个“服务依赖”......但是如果B不可用,A该怎么办?在 OSGi 中,我们可以安排如果 B 不可用,那么 A 也不可用——假设依赖是强制性的;我们还可以支持可选依赖项。另一方面,在使用 ServiceLoader 时,服务 A 无法控制其可用性,只要包含它的 JAR 在类路径中……因此即使在没有所需的“后端”服务的情况下,它也必须提供其功能。
ServiceLoader 要记住的另一件事是尝试抽象查找机制。发布机制非常好,干净且具有声明性。但是查找(通过 java.util.ServiceLoader)非常丑陋,它被实现为一个类路径扫描器,如果您将代码放入任何不具有全局可见性的环境(例如 OSGi 或 Java EE),它就会严重中断。如果您的代码与此纠缠不清,那么您以后将很难在 OSGi 上运行它。最好写一个你可以在时机成熟时替换的抽象。