osgi - Osgi ConfigurationAdmin 延迟激活组件
问题描述
我有一项需要配置的服务
@Component(service=InstrumenterService.class ,configurationPid = "InstrumenterService", configurationPolicy = ConfigurationPolicy.REQUIRE, scope = ServiceScope.PROTOTYPE)
public class InstrumenterService
该服务在另一个服务中被引用:
@Component(service = SampleService.class, scope = ServiceScope.PROTOTYPE)
public class SampleService {
@Reference(cardinality = ReferenceCardinality.OPTIONAL, scope = ReferenceScope.PROTOTYPE_REQUIRED, policyOption = ReferencePolicyOption.GREEDY)
InstrumenterService coverageInstrumenter;
public boolean hasInstrumenter() {
if(coverageInstrumenter == null)
return false;
return true;
}
}
此 SampleService 用于挂接到主 osgi 线程的 Main 类中。我正在使用 ComponentServiceObjects,因为我想按需创建 SampleServices。
@Component(immediate = true, property = "main.thread=true")
public class Main implements Runnable {
@Reference
ConfigurationAdmin cfgAdm;
@Reference(scope = ReferenceScope.PROTOTYPE_REQUIRED)
private ComponentServiceObjects<SampleService> sampleServices;
public void run() {
if (cfgAdm != null) {
Configuration configuration;
try {
configuration = cfgAdm.getConfiguration("InstrumenterService", "?");
Hashtable<String, Object> props = new Hashtable<>();
props.put("some_prop", "some_value");
configuration.update(props);
} catch (IOException e1) {
e1.printStackTrace();
}
}
SampleService servicess = sampleServices.getService();
System.out.println(servicess.hasInstrumenter());
}
}
我遇到的问题是 ConfigurationAdmin 设置的配置在 InstrumenterService 中不可见,除非我放置一个 Thread.sleep(500); 调用 configuration.update 后的命令。
我不太习惯使用 Thread.sleep 命令来确保配置更新可见。是否有 API 来检查配置是否已更新并且可以使用?
感谢尼尔,我能够找到一个可行的解决方案。在配置设置为等待服务后,我使用了 ServiceTracker:
BundleContext bundleContext = FrameworkUtil.getBundle(getClass()).getBundleContext();
ServiceTracker serviceTracker = new ServiceTracker(bundleContext, InstrumenterService.class.getName(), null);
serviceTracker.open();
try {
serviceTracker.waitForService(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
serviceTracker.close();
我首先需要 ConfigurationAdmin 的原因是因为有一个接口 IInstrumenter 可以由许多不同的类实现。该仪器的名称在 ConfigurationAdmin 中设置,然后在其他服务中进一步“自动”获取所需的仪器服务。
这样,可以将任意数量的仪器添加到应用程序中,并且只需要知道仪器的名称才能使用它。
我还想提一下,通过 OSGI,我们设法将我们的单体遗留应用程序拆分为更多模块(约 15 个),它们不直接相互依赖,而是使用 API 层。
再次感谢您使用 OSGI 所做的出色工作。
解决方案
正如评论中所阐明的那样,此代码并不完全现实。在生产代码中,通常不需要更新配置记录,然后立即获取组件发布的服务。这是因为任何这样的代码都对配置更新的效果做出了太多的假设。
调用getServiceReference
并getService
仅返回特定时刻服务注册表状态的快照。getService
调用期望它返回一个值本质上是不可靠的。
实际上,我们总是使用一种模式,当我们收到服务存在的通知时会做出反应。这可以通过多种方式完成,包括ServiceListener
and ServiceTracker
,但最简单的是编写一个带有引用的组件,例如:
@Component
public class MyComponent {
@Reference
SampleService service;
public void doSomething() {
println(service.hasInstrumenter());
}
}
这个组件有一个强制引用,并且只有当一个实例可用SampleService
时才会被激活。SampleService
推荐阅读
- prestashop - 如何在 prestashop 自定义块上获取当前产品链接?
- python - 如何从上下文中获取视图中对象的id?
- c - K&R 练习 1-8 改进
- angular - 表单以角度提交后,另一个页面中的成功消息
- c# - C# IF 语句双重结果
- python - 如何计算我要生成的文本文件的文件大小?
- python - TensorFlow 伪逆不适用于复杂矩阵
- ocaml - OCaml:表达式周围的括号是什么意思 [x]?
- r - bookdown gitbook 格式:侧边栏的文本标题和 ToC 的不同文本?
- python - 运行 Django 管理命令的 Fabric2 问题