我有一个 OSGi 组件 MyComponent

该组件引用了服务 MyService 。现在 MyService 有几个实现 MyServiceImpl1MyServiceImpl2MyComponent 也有属性 MyProperty

现在我想要的是,只要 MyProperty 为 1, MyComponent.MyService 就会绑定(bind)到 MyServiceImpl1 。如果我将 MyProperty 更改为 2,MyComponent.MyService 会动态更新 MyService 绑定(bind)到 `MyServiceImpl2。

我如何实现这一目标?作为引用,我使用的是 Apache Felix 容器,并且希望避免使用较低级别的 OSGi api。

最佳答案

配置依赖项的最简单方法是使用“.target”属性。这要求实现注册一个识别属性,比如 impl=1 。和 impl=2

@Component(property="impl=1")
public class MyServiceImpl1 implements MyService {
}
@Component(property="impl=2")
public class MyServiceImpl2 implements MyService {
}

该组件可能如下所示:
@Component
public class MyComponent {
    @Reference(target="(impl=1)")
    volatile MyService myService;
}

在这种情况下,您将无法使用 1 或 2 作为标志,但您必须使用另一个过滤器修改名称为 MyComponentmyService.target 的配置属性。 (这与 OSGi 标准化注释一起显示。)

如果您坚持 select 的属性为 1 或 2(让我们称其为 MyComponent ),那么它会更加复杂。首先我们有满足的问题。根据选择属性 impl 1 但只有 2 可用时,是否应该满足 MyComponent 需要?如果没问题,那么下面更复杂的解决方案应该可以工作
@Designate( ocd=Config.class )
@Component( property = "select=1" )
public class MyComponent {
      static Class<?> types [] = {
          MyServiceImpl1.class,
          MyServiceImpl2.class,
      };
      @interface Config {
          int select() default 1;
      }

      @Reference(target="(|(impl=1)(impl=2))")
      volatile List<MyService> candidates;

      volatile MyService selected;

      @Activate
      @Modify
      void changed( Config config ) {
          Class<?> type = types[config.select()];
          Optional<MyService> service = candidates.
              stream().
              filter( type::isInstance ).
              findFirst();
          this.service = service.isPresent() ? service.get() : null;
      }
}

如您所见,让组件开始处理自己的依赖项通常是一个坏主意。因此,我对您的真实世界场景感到好奇。

我发现在组件对引用对象很挑剔的情况下,维护设计总是非常尴尬和困难。有时这是不可避免的,但在一般解决方案中,MyServiceImpl2MyServiceImpl1 根据某些条件决定是否注册更能反射(reflect)现实。

所以我有一个大问题,1 或 2 属性在现实世界中反射(reflect)了什么?这不能建模为服务依赖项吗?

(免责声明:代码未经测试,没有错误处理)

关于osgi - 如何动态更新 OSGi 组件中的引用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37940008/

10-11 20:40