我在OSGi上下文中遇到了我不理解的声明式服务问题。我尝试解释一下:

我有一个FooService,它需要FooManagerService (1..1 static)FooManagerService引用了FooService,但它是可选的(0..n dynamic)
目标是,如果FooService可用,它将在bind()处注册(调用FooManagerService方法),以便FooManagerService始终具有系统中所有可用FooService实现的列表。

它在Windows上运行良好,但是在Linux上我遇到了问题,即FooService处于 Activity 状态(调用了activate()方法),但是FooManagerService无法识别(未调用bind()方法)。如果我在OSGi控制台上手动禁用和启用FooService,则FooManagerService会识别它​​。

我不明白,为什么会这样。通过增加FooServiceImpl所在的包的开始级别,可以避免这种情况。但这似乎是一个丑陋的解决方法,这就是为什么我想了解那里发生了什么。

我附上一张描述服务之间引用的图片。任何提示表示赞赏。提前致谢!

最好的祝福

斯特菲

Service Manager Diagram

最佳答案

根据理论,这里有一个周期应该可以。但是,实践中存在许多问题。

首先,您的实现应为immediate=true。这解决了一些问题,因为它避免了由于初始化DS而无法获得服务的麻烦问题。即如果FooManager和FooService impls必须是立即的。这在OSGi enRoute Cycles中描述

但是,还有一个问题:-( Apache Felix DS有一个错误,该错误会引起您所描述的影响。该错误与 bundle 包订购有关。在Apache Felix JIRA 5618中报告了此错误。

如果该DS错误是问题所在,那么很遗憾只有一个可靠的解决方案。不幸的是,因为它要求您下降到OSGi的肠子。解决方案是手动注册经理服务,并确保DS未注册该服务:

@Component(service={}, immediate=true )
public class FooManagerImpl implements FooManager {

   private ServiceRegistration<FooManager> registration;

   @Reference
   volatile List<FooService> foos;

   @Activate
   void activate( BundleContext context, Map<String,Object> properties ) {
     registration = context.registerService(FooManager.class, this, new Hashtable<String,Object>(properties));
   }

   @Deactivate
   void deactivate() {
      registration.unregister();
   }

   ...
}

这里的窍门是FooManager在激活之前不会注册其服务,而通常在激活之前先注册它。

我知道Apache Felix正在开发它,但不知道它们有多远。

无论如何,周期总是很烂。可悲的是,它们并非总是可以预防的,但是我一定会尝试。

10-04 17:41