【问题标题】:OSGI Declarative Services (DS): What is a good way of using service component instancesOSGI 声明式服务 (DS):什么是使用服务组件实例的好方法
【发布时间】:2010-11-09 07:40:53
【问题描述】:

我刚刚开始使用 Equinox 和 Eclipse PDE 使用 OSGI 和声明式服务 (DS)。

我有 2 个捆绑包,A 和 B。 Bundle A 公开了一个由 Bundle B 使用的组件。两个 bundle 也再次将此服务公开给 OSGI 服务注册表。

到目前为止一切正常,Equinox 正在将组件连接在一起,这意味着 Bundle A 和 Bundle B 由 Equinox 实例化(通过调用默认构造函数),然后使用 bind / unbind 方法进行连接。

现在,由于 Equinox 正在创建这些组件/服务的实例,我想知道获取此实例的最佳方法是什么?

所以假设有 third class 没有被 OSGI 实例化的类:

类 WantsToUseComponentB{
公共无效 doSomethingWithComponentB(){
 // 我如何获得组件B???可能是这样的?
 ComponentB 组件 = (ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName());
}

我现在看到以下选项:



1.在 Activator 中使用 ServiceTracker 来获取 ComponentBundleA.class.getName() 的服务(我已经尝试过了,它可以工作,但对我来说似乎开销很大)并通过静态工厂方法使其可用

公共类激活器{ 私有静态ServiceTracker组件BServiceTracker; 公共无效开始(BundleContext上下文){ componentBServiceTracker = new ServiceTracker(context, ComponentB.class.getName(),null); } 公共静态组件B getComponentB(){ 返回 (ComponentB)componentBServiceTracker.getService(); }; }

2。创建某种注册表,其中每个组件在调用 activate() 方法后立即注册。

公共组件B{ 公共无效绑定(组件A组件A){ someRegistry.registerComponent(this); }

公共组件B{ 公共无效激活(组件上下文上下文){ someRegistry.registerComponent(this); } }

}

3。使用 osgi / equinox 中的现有注册表,其中包含这些实例?我的意思是 OSGI 已经在创建实例并将它们连接在一起,所以它已经在某个地方拥有了对象。但是哪里?我怎样才能得到它们?

结论 WantsToUseComponentB 类(它不是组件,也不是由 OSGI 实例化)从哪里获得 ComponentB 的实例?是否有任何模式或最佳实践?正如我所说,我设法在 Activator 中使用了 ServiceTracker,但我认为没有它也是可能的。

我正在寻找的实际上是类似 Springframework 的 BeanContainer 之类的东西,我可以在这里说类似 Container.getBean(ComponentA.BEAN_NAME) 之类的东西。但我不想使用 Spring DS。

我希望这已经足够清楚了。否则我也可以贴一些源代码进行更详细的解释。

谢谢 克里斯托夫


更新: 回复尼尔的评论:

感谢您针对原始版本澄清这个问题,但我认为您仍然需要说明为什么不能通过 DS 之类的东西创建第三类。

嗯,不知道。也许有一种方法,但我需要将我的整个框架重构为基于 DS,以便不再有“new MyThirdClass(arg1, arg2)”语句。 真的不知道该怎么做,但我在 DS 中读到了一些关于 ComponentFactories 的内容。所以不要做一个

MyThirdClass 对象 = new MyThirdClass(arg1, arg2);

我可能会做一个

ComponentFactory myThirdClassFactory = myThirdClassServiceTracker.getService(); // 返回一个 if (myThirdClassFactory != null){ MyThirdClass 对象 = objectFactory.newInstance(); object.setArg1("arg1"); object.setArg2("arg2"); } 别的{ // 这里我可以假设 ComponentA 或 B 的某些服务消失了,因此无法创建 MyThirdClass 组件,因为缺少依赖项? }

在撰写本文时,我并不确切知道如何使用 ComponentFactories,但这应该是某种伪代码 :)

谢谢 克里斯托夫

【问题讨论】:

    标签: java service osgi declarative equinox


    【解决方案1】:

    克里斯托夫,

    感谢您针对原始版本澄清这个问题,但我认为您仍然需要说明为什么不能通过 DS 之类的东西创建第三类。

    DS 导致组件作为服务发布,因此从 DS 中“获取”任何组件的唯一方法是通过服务注册表访问它。不幸的是,使用较低级别的 API 可能很难正确使用服务注册表,因为它是动态的,因此您必须应对服务消失或在您希望它们可用时不可用的可能性,等等.这就是 DS 存在的原因:它为您提供了一个抽象,用于依赖服务并根据组件引用的服务的可用性来管理组件的生命周期。

    如果您确实需要在不使用 DS 或类似的东西的情况下访问服务(并且有很多“类似的东西”可供选择,例如 Spring-DM、iPOJO、Guice/Peaberry 等),那么您应该使用 ServiceTracker。我同意有很多开销——这也是 DS 存在的原因。

    要回答您的建议(2),不,您不应该创建自己的服务注册表,因为服务注册表已经存在。如果您创建了一个单独的并行注册表,那么您仍然必须处理所有动态,但您必须在两个地方而不是一个地方处理它。这同样适用于建议 (3)。

    我希望这会有所帮助。

    问候, 尼尔

    更新:顺便说一下,尽管 Spring 有 Container.getBean() 后门,但您注意到在所有 Spring 文档中强烈建议不要使用该后门:要获取 Spring bean,只需创建另一个引用它的 bean .这同样适用于 DS,即获取 DS 组件的最佳方式是创建另一个 DS 组件。

    还要注意,在 OSGi 世界中,即使您使用的是 Spring-DM,也没有简单的方法来调用 getBean(),因为您需要首先获取 Spring ApplicationContext。这本身就是一个 OSGi 服务,那么如何获得该服务呢?

    【讨论】:

    • 谢谢你回答尼尔。好的,假设第三类是我自己的遗留框架中的某个类,并且有一个对象无法由 DS 创建。我想知道静态ServiceTracker和Activator内部的静态工厂方法的方式是不是好方法?对我来说,这似乎有点hacky,但不知道为什么。不想到处使用静态服务跟踪器,但现在我就是这样做的。有更好的方法吗?我想有:) 谢谢克里斯托夫
    • 嗨,尼尔,我再次更新了问题(请参阅底部的更新)以回答您最初的问题。
    【解决方案2】:

    克里斯托夫, 不知道我是否真的理解你的问题。 每个前。 Bundle A 正在使用 DS 组件提供服务:

    <service>
      <provide interface="org.redview.lnf.services.IRedviewLnfSelectedService"/>
    

    Bundle B 需要这个使用 DS 组件的服务:

    <implementation class="ekke.xyz.rcp.application.internal.XyzApplicationLnfComponent"/>
    

    一旦 Bundle A 提供了 Service,Bundle B 通过实现类的 bind() 方法“获取”它:

    public class XyzApplicationLnfComponent {
    public void bind(IRedviewLnfSelectedService lnfSelectedService) {
        // here it is
    }
    

    希望这会有所帮助 哎呀

    【讨论】:

    • bundle B 也需要该服务(发布我的答案后线路“消失”)
    • 感谢 Ekke 的回答:我用更多细节和代码示例更新了我的问题。我感兴趣的实际上是这样的第 3 类:
      Class WantsToUseComponentB{ public void doSomethingWithComponentB(){ // 我如何获得 componentB ???可能是这样的? ComponentB 组件 = (ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName()); } 
      你能再看看吗?谢谢克里斯托夫
    【解决方案3】:

    简单方法:使用 Riena 将 DS 组件注入到您的 Activator 类中: http://wiki.eclipse.org/Riena_Getting_Started_with_injecting_services_and_extensions

    然后你可以从任何地方调用它:Activator.getDefault().getWhateverService()

    【讨论】:

      猜你喜欢
      • 2012-10-01
      • 2014-04-16
      • 2016-10-07
      • 2015-12-05
      • 1970-01-01
      • 2012-04-27
      • 2016-08-26
      • 2011-12-02
      • 1970-01-01
      相关资源
      最近更新 更多