【问题标题】:Best way to handle dynamic OSGi service dependencies处理动态 OSGi 服务依赖关系的最佳方法
【发布时间】:2015-07-15 15:54:31
【问题描述】:

我有一个看起来像这样的可选服务依赖项:

@Component
class TestComponent {
  private AtomicReference<TestService> testServiceRef;

  @Reference(type = '?')
  protected void setTestService(TestService testService) {
    testServiceRef.set(testService);
  }
  protected void unsetTestService(TestService testService) {
    testServiceRef.set(null);
  }

  public void doStuff() {
    TestService testService = testServiceRef.get();
    if (testService != null)
      testService.performSomeTask();
  }
}

现在如果在 testService.performSomeTask() 运行时服务变得未绑定,我有问题,对吗?我需要在所有这些函数中添加同步块,还是有更好的方法来处理这种情况?

【问题讨论】:

  • 我认为没有答案,因为您在示例中提供了最知名的方式(使用 AtomicReference)。由于 AtomicReference 在内部使用 volatile 变量,我认为在不久的将来有必要检查 volatile 或 synchronized 块在支持 Intel TSX-NI 的最新 Intel CPU 上是否更快。 Java 1.8.0_25 支持具有短同步块的 TSX-NI,但我不确定是否可以使用 volatile 变量实现相同的性能改进。
  • 为什么您认为除了使用 AtomicReference 之外还需要同步?
  • @BalazsZsoldos AtomicReference 不是简单地使用 volatile 变量实现的;它使用本机 CAS 指令。无论如何,性能真的不是这里的问题......服务发布每秒发生多少次?
  • @NeilBartlett AtomicReference 类中的 value 成员变量是 volatile。 getset 函数直接使用这个变量,我不知道Java 8 的TSX-NI 实现是否可以增强对volatile 变量的访问。 compareAndSetlazySet 等函数使用 Unsafe 类(至少在 OpenJDK 中)。

标签: java osgi declarative-services


【解决方案1】:

您不需要使用同步原子引用。我通常建议对具有动态策略的 DS 引用使用原子引用。

话虽如此,您的代码有两个问题:

  1. testServiceRef 字段从未初始化。您应该在构建过程中对其进行初始化,最好设置为final
  2. unsetTestService 的实现不正确。在动态服务替换期间,“新”服务的绑定发生在“旧”服务的解除绑定之前。因此,您需要检查未绑定的服务是否实际上是您当前绑定的服务。您可以致电testServiceRef.compareAndSet(testService, null) 来完成此操作。

【讨论】:

  • 谢谢尼尔。如果在 performSomeTask() 运行时卸载了包含 TestService 实现的包,会有什么问题吗?
  • 并非如此。服务调用可能会抛出异常,但作为服务的使用者,您应该始终准备好该服务不可靠。