首页 文章

OSGI声明服务(DS):使用服务组件实例的好方法是什么

提问于
浏览
5

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

我有2个Bundle,A和B. Bundle A公开了Bundle B使用的组件 . 这两个bundle也将这个服务再次公开给OSGI Service注册表 .

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

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

所以假设有一个 third class 类,它不是由OSGI实例化的:

Class WantsToUseComponentB{
public void doSomethingWithComponentB(){
 // how do I get componentB??? Something like this maybe?
 ComponentB component = (ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName());
}

我现在看到以下选项:

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

public class Activator{

   private static ServiceTracker componentBServiceTracker;   

   public void start(BundleContext context){

     componentBServiceTracker = new ServiceTracker(context, ComponentB.class.getName(),null);
   }

   public static ComponentB getComponentB(){
     return (ComponentB)componentBServiceTracker.getService(); 
   };

}

2. Create some kind of Registry 其中每个组件在调用activate()方法后立即注册 .

public ComponentB{

public void bind(ComponentA componentA){
   someRegistry.registerComponent(this);
}

要么

public ComponentB{

   public void activate(ComponentContext context){
      someRegistry.registerComponent(this);
   }

}

}

3. Use an existing registry inside osgi / equinox 哪些实例?我的意思是OSGI已经在创建实例并将它们连接在一起,所以它已经有了某些对象 . 但是哪里?我怎么能得到它们?

ConclusionWantsToUseComponentB (不是组件而不是OSGI实例化)从哪里获取ComponentB的实例?有任何模式或最佳实践吗?正如我所说,我设法在Activator中使用ServiceTracker,但我认为没有它就可以实现 .

我正在寻找的实际上就像Springframework的BeanContainer,我可以说像Container.getBean(ComponentA.BEAN_NAME) . 但我不想使用Spring DS .

我希望这很清楚 . 否则我也可以发布一些源代码来更详细地解释 .

谢谢Christoph


UPDATED: 回答尼尔的评论:

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

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

MyThirdClass object = new MyThirdClass(arg1, arg2);

我可能会这样做

ComponentFactory myThirdClassFactory = myThirdClassServiceTracker.getService(); // returns a 

if (myThirdClassFactory != null){
  MyThirdClass object = objectFactory.newInstance();

   object.setArg1("arg1");
  object.setArg2("arg2");
}
else{
 // here I can assume that some service of ComponentA or B went away so MyThirdClass Componenent cannot be created as there are missing dependencies?

}

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

谢谢Christoph

3 回答

  • 1

    克里斯托夫,

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

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

    如果你真的需要在不使用DS或其类似东西的情况下访问服务(并且有很多类似的东西,例如Spring-DM,iPOJO,Guice / Peaberry等)那么你应该使用ServiceTracker . 我同意有很多开销 - 再次,这就是DS存在的原因 .

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

    我希望这有帮助 .

    问候,尼尔

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

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

  • 7

    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

  • 0

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

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

相关问题