我正在使用ServiceTracker来定位OSGi环境中的注册服务。 我在Bundle Activator启动方法中得到了这段代码:
logger.debug("looking for MyService");
tracker = new ServiceTracker(ctx, MyService.class.getName(), null);
tracker.open();
MyService = ((MyService)tracker.getService());
if (MyService != null)
{
logger.debug("found MyService");
}
问题在于:
我认为问题不在于托管MyService的捆绑包,因为它显然存在,如果我的捆绑包重新启动,可以再次找到它。
看起来我的bundle在拥有依赖服务的bundle之前加载,这就是为什么它在重启后无法找到它并且在我重新启动bundle之后可以找到它。
如果我使用
列出可用服务,则表明这一点ServiceReference[] ref = tracker.getServiceReferences();
它在OSGi重新启动后没有找到任何服务,但是在我停止/启动查找它的bundle后它确实找到了MyService。
我试图将Require-Bundle引用设置为托管MyService的bundle,希望OSGi框架能够识别依赖,但它没有帮助。
任何想法......?
答案 0 :(得分:4)
如果您使用ServiceTracker
中的BundleActivator
,则可以有效地冻结整个框架(因此,不能同时启动其他捆绑包)。如果提供服务的软件包在与跟踪器捆绑后启动,则您将看不到该服务。这解释了为什么稍后停止和启动您的捆绑包会为您提供服务。
现在,如果您想跟踪和使用该服务,我会生成一个新线程来执行此操作,并使用waitForService
代替getService
。
答案 1 :(得分:2)
使用ServiceTracker做正确的事情。但问题是期望服务器是跟踪器在激活器中可用。您不希望在启动捆绑包和注册服务的捆绑包之间建立排序约束。除非你真的需要在激活器的启动方法中使用该服务(并且你可能不应该),否则只需在实际需要时获得服务。
另一个想法是考虑使用Declarative Services来管理您的服务依赖项。
答案 2 :(得分:1)
OSGi中的服务非常不稳定,所以你永远不要指望一个人在你需要的时候就在那里,或者在你得到它之后留在那里。这就是为什么你的捆绑包应该让自己异步通知服务。
ServiceTracker
类接受一个ServiceTrackerCustomizer
(并且是一个),当服务来来往往时会收到通知。
大多数情况下,使用服务跟踪器的正确方法如下:
// In BundleActivator.start:
this.serviceTracker = new ServiceTracker(bundleContext, MyService.class.getName(), null) {
public Object addingService(ServiceReference reference) {
// Get the service
final MyService service = (MyService)this.context.getService(reference);
// Do something with the service (e.g. inject it somewhere)
// ...
// Return the service to track it
return service;
}
public void removedService(ServiceReference reference, Object service) {
// Stop using the service (e.g. notify the objects that use it)
// ...
// Unget the service (very important!)
this.context.unget(reference);
}
}
请注意,我们只跟踪MyService
服务并且不使用任何自定义程序(我们将null
作为第三个参数传递给构造函数),而是覆盖两个重要的方法。另一个重要的方法是modifiedService
;请阅读Javadoc以获取更多信息。
管理这个很快就会成为一个严重的负担,所以你应该考虑使用更高级别的抽象,比如声明性服务(正如另一个答案所建议的那样)。