Java 如何使用OSGi标准功能以编程方式在SCR中注册服务?

Java 如何使用OSGi标准功能以编程方式在SCR中注册服务?,java,osgi,Java,Osgi,我花了一些时间试验和研究OSGi途中站点。课程和教程都非常好。现在,作为一个学习练习,我将按照这些教程中的原则创建自己的示例 我决定从博客文章“”中复制StageService。与使用org.apache.felix.dm和org.apache.felix.dm.annotation.api包不同,我希望使用OSGi标准SCR包(org.OSGi.service.component.*)和途中提供程序模板 到目前为止,一切进展顺利。但有一点我被卡住了。在“使用OSGi改进JavaFX”教程中,使

我花了一些时间试验和研究OSGi途中站点。课程和教程都非常好。现在,作为一个学习练习,我将按照这些教程中的原则创建自己的示例

我决定从博客文章“”中复制
StageService
。与使用
org.apache.felix.dm
org.apache.felix.dm.annotation.api
包不同,我希望使用OSGi标准SCR包(
org.OSGi.service.component.*
)和途中提供程序模板

到目前为止,一切进展顺利。但有一点我被卡住了。在“使用OSGi改进JavaFX”教程中,使用
org.apache.felix.dm.DependencyManager以编程方式将服务注册到服务注册中心,如下所示:

 @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
是ApacheFelix特有的特性,而不是OSGi标准。我希望我的途中提供商只依赖OSGi标准功能

所以我的问题很简单:

  • 如何仅使用OSGi标准功能以编程方式在服务注册表中注册服务?(我从沿途教程中了解到,如果我的组件实现了导出的服务,当我的组件被激活时,SCR将自动在服务注册表中注册我的组件。不过,这个解决方案的问题是,当我的组件被激活时,它必须在不同的线程中启动JavaFX应用程序,以便在JavaFX应用程序终止之前,不阻止SCR使用的线程。因此,我的组件必须以编程方式在服务注册表中注册该服务。否则,它将无法保证在注册时可用。)
  • 作为参考,以下是我目前拥有的:

    private void registerService(Stage stage) {
        DependencyManager dm = new DependencyManager(bundle().getBundleContext());
        dm.add(
            dm.createComponent()
              .setInterface(StageService.class.getName(), null)
              .setImplementation(new StageServiceImpl(primaryStage))
        );
    }
    
    但我想用这个来代替它:

    private void registerService(Stage stage) {
        // How to register service in service registry using only OSGi standard features? (not the apache felix dependency manager)
    }
    
    更新1

    根据BJ Hargrave的建议,我尝试直接从bundle上下文注册服务,如下所示:

    FrameworkUtil
      .getBundle(getClass())
      .getBundleContext()
      .registerService(StageService.class, new StageServiceImpl(primaryStage), null);
    
    执行此操作并尝试解决途中应用程序项目后,出现以下错误:

    org.osgi.service.resolver.ResolutionException:无法解析 version=null:缺少需求 com.github.axioptiy.osgi.javafx.launcher.application ->无法解析com.github.axiopisty.osgi.javafx.launcher.application 版本=1.0.0.201608172037:缺少要求 objectClass=com.github.axioptiy.osgi.javafx.launcher.api.StageService]

    我已将项目上载到,以便您可以重现错误

    更新2

    提供程序模块中bnd.bnd文件中的“生成”选项卡显示以下警告:

    The servicefactory:=true directive is set but no service is provided, ignoring it
    

    这可能与无法解决的应用程序模块有关吗?

    阅读OSGi规范将帮助您理解服务API

    但这应该做到:

    ServiceRegistration reg=bc.registerService(StageService.class,新的StageServiceImpl(primaryStage),null);
    

    在极少数情况下,需要使用标准OSGiAPI注册“手动服务”。尽量避免这种情况,因为如果您开始注册(或者可能依赖)手动注册的服务,您将承担很多通常隐藏在视图之外的责任。例如,您必须确保您注册的服务也未注册

    其中一种罕见的情况是,在注册服务之前,您必须等待条件。例如,在为设备注册服务之前,需要轮询硬件。您需要控制CPU,但此时还无法注册服务。在这种情况下,您将创建一个
    立即
    组件并手动注册服务

    要手动注册服务,您需要一个
    BundleContext
    对象。您可以通过activate方法获取该对象,只需在其参数中声明一个Bundle上下文,它就会被自动注入:

    @Activate
    void activate( BundleContext context) {
        this.context = context;
    }
    
    现在,您可以在bundle上下文中注册服务:

    void register(MyService service) {
        Hashtable<String,Object> properties = new Hashtable<>();
        properties.put("foo", "bar");
        this.registration = context.registerService( MyService.class, service, properties );
    }
    
    如果您创建的服务是回调线程或后台线程,那么您显然必须处理并发性问题。您必须确保不存在在停用方法完成时注册服务的竞争条件


    此文本也已添加到OSGi途中的版本中

    我确实尝试过,但provider模块bnd.bnd文件中的build选项卡声明:设置了servicefactory:=true指令,但未提供serive,将忽略它。“运行”选项卡可以很好地解决问题。但是当我尝试解析应用程序模块时,我得到:…ResolutionException:无法解析version=null:缺少需求com.github.axiopsty.osgi.javafx.launcher.application->无法解析com.github.axiopsty.osgi.javafx.launcher.application version=1.0.0.201608172025:缺少需求objectClass=com.github.axioptiy.osgi.javafx.launcher.api.StageService]您询问了如何使用OSGiAPI注册服务。然后我展示了。现在你在问另一个问题,我不确定我是否理解。我不知道您正在使用的示例的详细信息,因此我无法真正提供帮助。您的应用程序引用了StageService:。这将导致生成的bundle在其清单中声明osgi.service需求。由于提供程序不使用DS提供服务(您正在使用OSGi注册它),因此解析程序找不到任何人提供服务。您可以将服务的提供功能添加到提供商的清单中。我接受了您的回答,因为它确实回答了我原来帖子中的问题。非常感谢。但是,我在运行这个示例时仍然遇到问题。您是否介意在github存储库上提交一份PR,向我展示如何让应用程序以提供功能和要求的方式运行
    @Deactivate
    void deactivate() {
       if ( this.registration != null)
         this.registration.unregister();
    }