我有一个 OSGi 组件 MyComponent
。
该组件引用了服务 MyService
。现在 MyService
有几个实现 MyServiceImpl1
和 MyServiceImpl2
。 MyComponent
也有属性 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 作为标志,但您必须使用另一个过滤器修改名称为
MyComponent
的 myService.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;
}
}
如您所见,让组件开始处理自己的依赖项通常是一个坏主意。因此,我对您的真实世界场景感到好奇。
我发现在组件对引用对象很挑剔的情况下,维护设计总是非常尴尬和困难。有时这是不可避免的,但在一般解决方案中,
MyServiceImpl2
和 MyServiceImpl1
根据某些条件决定是否注册更能反射(reflect)现实。所以我有一个大问题,1 或 2 属性在现实世界中反射(reflect)了什么?这不能建模为服务依赖项吗?
(免责声明:代码未经测试,没有错误处理)
关于osgi - 如何动态更新 OSGi 组件中的引用?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37940008/