6

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

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

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

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

所以假设有没有被 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 但这应该是某种伪代码 :)

谢谢克里斯托夫

4

3 回答 3

7

克里斯托夫,

感谢您针对原始版本澄清这个问题,但我认为您仍然需要说明为什么不能通过 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 服务,那么如何获得该服务呢?

于 2009-07-09T11:21:39.797 回答
1

christoph,不知道我是否真的理解你的问题。每个前。Bundle A 使用 DS 组件提供服务:

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

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

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

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

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

希望这有助于ekke

于 2009-07-09T10:39:37.107 回答
0

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

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

于 2010-05-10T21:24:52.363 回答