我试图了解OSGi服务。我一直在问自己的主要问题是:使用服务而不是使用捆绑包及其导出的包有什么好处?
据我所知, Late Binding 的概念似乎与它有关。 Bundle依赖关系在bundle start处连接在一起,所以我猜它们非常固定。但随着服务似乎几乎相同。捆绑包启动并注册服务或绑定到服务。当然,服务可以随时出入,你必须跟踪这些机会。但核心思想对我来说似乎没有什么不同。
这方面的另一个方面似乎是服务更灵活。一个特定接口可能有许多实现。另一方面,对于特定的导出包也可能有很多不同的实现。
在另一篇文章中,我读到使用导出包的缺点是它们使应用程序比服务更脆弱。作者写道,如果从依赖图中删除一个包,则不再满足其他依赖关系,从而可能对整个图形造成多米诺骨牌效应。但是如果服务脱机会发生同样的情况吗?对我来说,看起来服务依赖性并不比bundle依赖性好。
到目前为止,我找不到可以清楚地描述为什么服务比通过导出和导入包公开功能更好的博客文章,书籍或演示文稿。
总结我的问题:
使用OSGi服务使其优于导出和导入包有哪些主要好处?
我试图收集有关此问题的更多信息,并在包和服务的普通导出/导入之间进行某种比较。也许这会帮助我们找到满意的答案。
开始/停止/更新
可以启动和停止捆绑包(因此包)和服务。除此之外,他们可以更新。服务也与捆绑生命周期本身有关。但在这种情况下,我只是说你可以启动和停止服务或捆绑(以便导出的包“消失”)。
跟踪变化
ServiceTracker和BundleTracker使跟踪和响应捆绑和服务可用性变化成为可能。
与其他捆绑包或服务的特定依赖关系。
如果要使用导出的包,则必须将其导入。
Import-Package: net.jens.helloworld
net.jens.helloworld 会提供一项服务,我还需要导入该软件包以获取界面。
因此,在这两种情况下,它们都会与某种或多或少的特定包装形成“紧密耦合”。
能够拥有多个实现
可以通过多个捆绑包导出特定包。可能有一个包 net.jens.twitterclient ,它由bundle A和bundle B导出。这同样适用于服务。接口 net.jens.twitterclient.TwitterService 可以由捆绑包A和B发布。
总结这里的简短比较(导出包/服务):
所以没有区别。
此外,似乎服务增加了更多的复杂性并引入了另一层依赖关系(请参阅下面的image)。
alt text http://img688.imageshack.us/img688/4421/bundleservicecomparison.png
因此,如果导出的包和服务之间没有真正的区别,那么使用服务的好处是什么?
我的解释:
服务的使用似乎更复杂。但服务本身似乎更轻巧。如果您启动/停止整个捆绑包或者您只是启动和停止特定服务,那么它应该是(在性能和资源方面)的差异。
从架构的角度来看,我也猜测捆绑包可以被视为应用程序的基础。在启动和停止捆绑方面,基础不应经常更改。该功能由该包的服务在“捆绑层”上方的某种动态层中提供。这个“服务层”可能会经常变化。例如,如果数据库脱机,则取消注册用于查询数据库的服务。
你有什么看法?我是开始得到服务的全部还是我还在想错误的方法?是否有我遗漏的东西会使服务比出口包更具吸引力?
答案 0 :(得分:6)
很简单: 捆绑包只提供您可以使用的类。使用Imports / Exports可以屏蔽可见性并避免(例如)版本控制冲突。 服务是满足特定合同(接口)的类实例。
因此,在使用服务时,您不必关心实现的起源或实现细节。当您使用某项服务时,它们甚至可能会发生变化。
当您只想依赖OSGi的Bundle Layer时,您可以轻松地将横切依赖项引入到您通常不想要的具体实现中。 (见下文关于DI)
这不仅仅是一个OSGi的东西 - 只是一个好习惯。
在非OSGi世界中,您可以使用Guise,Spring或类似的依赖注入(DI)框架。 OSGi在框架中内置了服务层,允许更高级别的框架(Spring,Guice)使用该层。 - 所以最后你通常不直接使用OSGi服务API,而是使用友好框架的DI适配器(Spring - > Spring DM,Guice - > Peaberry等)。
HTH, 托尼
答案 1 :(得分:4)
我建议购买这本书。它非常出色地解释了服务,并完成了使用OSGi服务的非平凡应用程序的构建。
我的公司经常使用服务构建100多个捆绑应用程序。我们从使用服务中获得的主要好处是:
1)生产者/消费者实施的松散耦合
2)热插拔服务提供商
3)清洁应用程序架构
答案 2 :(得分:2)
当你从OSGi开始时,总是更容易从一个export-package方法开始它当然感觉更像java。但是当你的应用程序开始增长并且你需要一些动态时,服务就是你的选择。
Export-package仅在启动时执行解析,而服务是持续解决(您可能需要或不需要)。从支持的角度来看,服务可能非常可怕(它是确定性的吗?我如何复制问题?),但它也非常强大。
Peter Kriens解释了为什么他认为服务是一种范式转变,就像OO当时一样。请参阅µServices和Duct Tape。
在我的所有OSGi经验中,我还没有机会实现复杂的服务(即多层),当然注释似乎还有很长的路要走。您还可以使用Spring dynamic module来减轻处理服务跟踪器的痛苦。 (以及许多其他选项,例如iPOJO和Blueprint)
答案 3 :(得分:0)
我认为这篇优秀文章可以回答您的很多问题: OSGi, and How It Got That Way 。
答案 4 :(得分:0)
让我们考虑以下两种情况:
Bundle A提供的服务是算术加法add(x,y) return x+y
。为此,它将“mathOpe包”导出为“IAddition接口”,并在服务注册表中注册服务。捆绑包B,C,D,...使用此服务。
Bundle A导出“mathOpe包”,我们在其中找到了一个暴露操作(x+y)<--add(x,y)
的类Addition。捆绑包B,C,D,...导入包mathOpe。
方案1与方案2的比较:
......等等。
PS:我不是OSGI专家,也不是Java专家,这个答案只显示了我对这些现象的理解:)
答案 5 :(得分:0)
使用服务而不是实现类的主要优点是提供服务的bundle将对类本身进行初始化。
使用该服务的捆绑包不需要知道有关如何初始化服务的任何信息。
如果您不使用服务,则必须始终调用工厂类型来创建服务实例。该工厂将泄露应保密的服务细节。