如何动态更新OSGi组件中的引用?
我有一个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
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
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;
}
}