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

如何动态更新OSGi组件中的引用?,osgi,apache-felix,Osgi,Apache Felix,我有一个OSGi组件MyComponent 此组件引用了一个服务MyService。现在MyService有两个实现myserviceinmpl1和myserviceinmpl2MyComponent还具有属性MyProperty 现在我想要的是,每当MyProperty为1时,MyComponent.MyService就会绑定到MyServiceImpl1。如果我将MyProperty更改为2,MyComponent.MyService会动态更新MyService绑定到'MyServiceIm

我有一个OSGi组件
MyComponent

此组件引用了一个服务
MyService
。现在
MyService
有两个实现
myserviceinmpl1
myserviceinmpl2
MyComponent
还具有属性
MyProperty

现在我想要的是,每当
MyProperty
为1时,
MyComponent.MyService
就会绑定到
MyServiceImpl1
。如果我将
MyProperty
更改为2,
MyComponent.MyService
会动态更新
MyService
绑定到'MyServiceImpl2'


我该怎么做?作为参考,我使用的是ApacheFelix容器,希望避免使用较低级别的OSGiAPI。

首先,您必须使用不同的过滤器发布您的实现,以便能够通过过滤获得一个或另一个。 然后,只要使用更改属性,就可以更改ServiceReference


技术细节取决于您使用的框架(DS、iPojo、none等)。

我假设可以查询MyService的实现,以报告其类型(例如,下面):

如果是这样,对于Apache Felix上的声明性服务OSGi组件,有一种方法:

  • MyService
    引用保留在
    MyComponent
    • Dynamic
      参考策略(
      Policy=ReferencePolicy.Dynamic
    • 1..n
      基数(
      cardinality=ReferenceCardinality.MANDATORY\u MULTIPLE
  • MyComponent
  • MyComponent
当Felix SCR实例化
MyService
实现时,
bind/unbind
MyComponent的方法将被调用。您可能希望维护可用实现的映射

每当有
MyComponent
的配置更新事件时,就会调用
Modified
方法。在此方法中,基于更新的组件配置属性,可以选择适当的方法进行进一步处理

这就是组件在使用时的外观

@组件(元类型=true,立即数=true)
@服务(值=MyComponent.class)
公共类MyComponent{
@属性(name=“impl.selector”,value=“impl_1”)
私有字符串implSelector=“impl_1”;
@参考文献(
referenceInterface=MyService.class,
policy=ReferencePolicy.DYNAMIC,
基数=ReferenceCardinality.MANDATORY\u倍数,
策略=参考策略.EVENT,
bind=“bindService”,
unbind=“unbindService”
)
私有映射availableMyServiceImpls=new HashMap();
私有MyService服务=null;
@激活
公共无效激活(ComponentContext ComponentContext){
service=availableMyServiceImpls.get(implSelector);
}
@停用
公共无效停用(ComponentContext ComponentContext){
availableMyServiceImpls.clear();
}
public void bindService(MyService serviceRef、Map refProperties){
字符串serviceImplName=(字符串)refProperties.get(MyService.NAME\u属性);
availableMyServiceImpls.put(serviceImplName,serviceRef);
}
public void unbindService(MyService serviceRef、Map refProperties){
字符串serviceImplName=(字符串)refProperties.get(MyService.NAME\u属性);
availableMyServiceImpls.remove(serviceImplName);
}
@修改
已修改公共void(ComponentContext ComponentContext){
Dictionary componentProps=componentContext.getProperties();
implSelector=PropertiesUtil.toString(componentProps.get(“impl.selector”),“”);
service=availableMyServiceImpls.get(implSelector);
}
}

配置依赖项的最简单方法是使用“.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作为标志,但必须使用另一个筛选器修改名为
myService.target
MyComponent
的配置属性。(这在OSGi标准化注释中显示。)

如果您坚持为
MyComponent
指定一个属性为1或2(我们称之为
select
),那么它就更复杂了。首先,我们有一个满意的问题。当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;
      }
}
@specify(ocd=Config.class)
@组件(property=“select=1”)
公共类MyComponent{
静态类类型[]={
MyServiceImpl1.class,
MyServiceImpl2.class,
};
@接口配置{
int select()默认值为1;
}
@引用(target=“(|(impl=1)(impl=2)))
不稳定的候选人名单;
选择易失性MyService;
@激活
@修改
无效已更改(配置){
Class type=types[config.select()];
可选服务=候选人。
流()。
筛选器(类型::isInstance)。
findFirst();
this.service=service.isPresent()?service.get():null;
}
}
正如您所看到的,组件开始处理自己的依赖项通常是一个坏主意。因此,我对你的真实世界很好奇

我发现,如果组件对引用对象很挑剔,那么维护设计总是非常尴尬和困难的。有时这是不可避免的,但在一般解决方案中,
myserviceinmpl2
myserviceinmpl1
决定注册或
@Component
public class MyComponent {
    @Reference(target="(impl=1)")
    volatile MyService myService;
}
@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;
      }
}