我在OSGi上下文中遇到了一个我不理解的声明性服务的问题。我试着解释一下:
我有FooService
需要FooManagerService (1..1 static)
。 FooManagerService
引用了FooService
,但它是可选的(0..n dynamic)
。
目标是,如果FooService
可用,则会在bind()
注册(FooManagerService
方法),以便FooManagerService
始终包含所有可用的列表{ {1}}系统中的实现。
它在Windows上运行良好,但在Linux上遇到问题,FooService
变为活动状态(FooService
方法被调用),但activate()
无法识别(不调用FooManagerService
方法)。如果我在OSGi控制台上手动禁用并启用bind()
,则FooService
会识别它。
我不明白,为什么会这样。可以通过增加捆绑包的起始级别来避免FooManagerService
所在的位置。但这感觉就像一个丑陋的解决方法,这就是为什么我想了解那里发生了什么。
我附上一张描述服务之间参考的图片。任何提示都表示赞赏。提前谢谢!
祝你好运
斯特芬
答案 0 :(得分:1)
根据理论,这里有一个循环应该没问题。但是,实践中存在许多问题。
首先,您的实施应该是immediate=true
。这解决了一些问题,因为它可以防止DS无法获得服务的令人讨厌的问题,因为它正在初始化。即如果FooManager和FooService impls必须是立即的。这在OSGi enRoute Cycles
然而,还有一个问题:-( Apache Felix DS有一个错误会导致你描述的效果。这个错误与包排序有关。这在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正在研究它,但不知道它们有多远。
无论如何,周期总是糟透了。可悲的是,它们并不总是可以预防,但我当然会尝试。
注意:手动注册服务不会创建功能。如果使用要求/功能,则应在清单中添加服务功能以使解析器工作。如果这条线对你来说是胡言乱语,请忽略它。