如何动态更新OSGi组件中的引用?

sdm*_*sdm 4 osgi apache-felix

我有一个OSGi组件MyComponent.

该组件引用了一项服务MyService.现在MyService有几个实现MyServiceImpl1MyServiceImpl2.MyComponent也有财产MyProperty.

现在我想要的是,只要MyProperty是1,就会MyComponent.MyService绑定MyServiceImpl1.如果我更改MyProperty为2,则MyComponent.MyService动态更新MyService绑定到"MyServiceImpl2".

我怎么做到这一点?作为参考,我使用的是Apache Felix容器,并且更愿意避免使用较低级别的OSGi api.

Pet*_*ens 7

配置依赖项的最简单方法是使用'.target'属性.这就要求实现注册一个标识属性impl=1.和impl=2.

@Component(property="impl=1")
public class MyServiceImpl1 implements MyService {
}
@Component(property="impl=2")
public class MyServiceImpl2 implements MyService {
}
Run Code Online (Sandbox Code Playgroud)

该组件可能看起来像:

@Component
public class MyComponent {
    @Reference(target="(impl=1)")
    volatile MyService myService;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您将无法使用1或2的国旗,但你将不得不修改配置属性MyComponent的名称myService.target与另一个过滤器.(这与OSGi标准化注释一起显示.)

如果你坚持使用1或2(我们称之为select)的属性,MyComponent那么它就更精细了.首先,我们有满足的问题.MyComponent是否应该根据select属性impl 1满足,但只有2可用?如果可以,那么以下更复杂的解决方案应该可行

@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;
      }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,组件开始处理自己的依赖关系通常是一个坏主意.因此,我对你的现实世界情景感到好奇.

我发现总是非常尴尬和难以维护设计,其中组件对于他们引用的人是挑剔的.它有时是不可避免的,但在一般的解决方案中,MyServiceImpl2并且MyServiceImpl1决定注册或不基于某些条件更好地反映现实.

所以我有一个大问题是1或2属性在现实世界中反映出来了什么?这不能被建模为服务依赖吗?

(免责声明:代码未经过测试且无错误处理)