我花了一些时间试验和研究OSGi enRoute网站。 Quick Start和Base教程非常好。现在作为一个学习练习,我正在按照这些教程中的原则创建我自己的例子。
我决定从博文“Making JavaFX better with OSGi”重现org.apache.felix.dm
。我想使用OSGi标准SCR软件包(org.apache.felix.dm.annotation.api
)以及enRoute提供程序模板,而不是使用org.osgi.service.component.*
和org.apache.felix.dm.DependencyManager
软件包。
到目前为止,一切都很顺利。但我坚持一点。在“使用OSGi更好地制作JavaFX”教程中,使用 @Override
public void start(Stage primaryStage) throws Exception {
BundleContext bc = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
DependencyManager dm = new DependencyManager(bc);
dm.add(dm.createComponent()
.setInterface(StageService.class.getName(), null)
.setImplementation(new StageServiceImpl(primaryStage)));
}
以这种方式将服务以编程方式注册到服务注册表中:
DependencyManager
我的假设是,在此示例中,private void registerService(Stage stage) {
DependencyManager dm = new DependencyManager(bundle().getBundleContext());
dm.add(
dm.createComponent()
.setInterface(StageService.class.getName(), null)
.setImplementation(new StageServiceImpl(primaryStage))
);
}
是Apache Felix特定功能,而不是OSGi标准。我想让我的enRoute提供程序仅依赖于OSGi标准功能。
所以我的问题很简单:
供参考,以下是我目前的情况:
private void registerService(Stage stage) {
// How to register service in service registry using only OSGi standard features? (not the apache felix dependency manager)
}
但我想用这个替换它:
FrameworkUtil
.getBundle(getClass())
.getBundleContext()
.registerService(StageService.class, new StageServiceImpl(primaryStage), null);
更新1
按照BJ Hargrave的建议,我尝试直接从捆绑上下文中注册服务,如下所示:
The servicefactory:=true directive is set but no service is provided, ignoring it
执行此操作并尝试解析enRoute应用程序项目后,会发生以下错误:
org.osgi.service.resolver.ResolutionException:无法解析 <> version = null:缺少要求 com.github.axiopisty.osgi.javafx.launcher.application - >无法解析com.github.axiopisty.osgi.javafx.launcher.application version = 1.0.0.201608172037:缺少要求 的objectClass = com.github.axiopisty.osgi.javafx.launcher.api.StageService]
我已将项目上传到github,以便您重现错误。
更新2
提供程序模块中bnd.bnd文件中的“构建”选项卡显示以下警告:
{{1}}
这可能与应用程序模块无法解决有关吗?
答案 0 :(得分:3)
在极少数情况下,有必要使用标准OSGi API注册“手工服务”。尽量避免这种情况,因为如果您开始注册(并且可能依赖)您手动注册的服务,您将承担很多责任,这通常是从视图中隐藏的。例如,您必须确保您注册的服务也未注册。
在极少数情况下,必须等待条件才能注册您的服务。例如,您需要在为设备注册服务之前轮询一块硬件。您将需要控制CPU,但此时您还无法注册服务。在这种情况下,您将创建一个immediate
组件并手动注册该服务。
要手动注册服务,您需要BundleContext
个对象。您可以通过activate方法获取该对象,只需在其参数中声明一个Bundle Context并自动注入:
@Activate
void activate( BundleContext context) {
this.context = context;
}
您现在可以使用捆绑上下文注册服务:
void register(MyService service) {
Hashtable<String,Object> properties = new Hashtable<>();
properties.put("foo", "bar");
this.registration = context.registerService( MyService.class, service, properties );
}
但是,您现在有责任在停用时取消注册此服务。如果您不清理此服务,那么当您的服务仍然浮动时,您的组件可能会被停用。您的服务非托管。 (虽然当捆绑停止时,它将被清除。)
@Deactivate
void deactivate() {
if ( this.registration != null)
this.registration.unregister();
}
如果您创建的服务是回调或后台线程,那么您显然必须处理并发问题。您必须确保在停用方法完成时没有注册服务的竞争条件。
此文本也已添加到OSGi enRoute的DS Page
答案 1 :(得分:1)
阅读OSGi规范将有助于您了解服务API。
但是应该这样做:
ServiceRegistration<StageService> reg = bc.registerService(StageService.class, new StageServiceImpl(primaryStage), null);