我在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正在开发它,但不知道它们有多远。
无论如何,周期总是很烂。可悲的是,它们并非总是可以预防的,但是我一定会尝试。