我正在使用 OSGi DS 组件和 ConfigurationAdmin。
我创建了一个简单的可配置组件
@Component(service=ConfigurableService.class)
public class ConfigurableService {
private String message;
@Activate
public void activate(Map<String, Object> params) {
System.out.println("Activate configurable");
message = (String) params.get("msg");
}
@Modified
public void modified(Map<String, Object> params) {
System.out.println("Modify configurable");
message = (String) params.get("msg");
}
@Deactivate
public void deactivate(Map<String, Object> params) {
System.out.println("Deactivate configurable");
message = (String) params.get("msg");
}
public void execute() {
System.out.println("Service says: " + message);
}
}
然后我创建了一个 Felix Gogo shell 命令组件来通过 ConfigurationAdmin 触发配置
@Component(property = {
CommandProcessor.COMMAND_SCOPE + "=fipro",
CommandProcessor.COMMAND_FUNCTION + "=configure"
},
service = ConfigurationCommand.class
)
public class ConfigurationCommand {
private ConfigurationAdmin cm;
@Reference(unbind="-")
public void setConfigAdmin(ConfigurationAdmin cm) {
this.cm = cm;
}
public void configure(String input) throws IOException {
Configuration config = cm.getConfiguration("org.fipro.osgi.config.ConfigurableService");
Hashtable<String, Object> props = new Hashtable<>();
props.put("msg", input);
config.update(props);
}
}
最后我创建了另一个 Felix Gogo shell 命令组件,它使用 ConfigurableService
@Component(property = {
CommandProcessor.COMMAND_SCOPE + "=fipro",
CommandProcessor.COMMAND_FUNCTION + "=welcome"
},
service = WelcomeCommand.class
)
public class WelcomeCommand {
private ConfigurableService service;
@Reference(unbind="-")
public void setConfigurable(ConfigurableService service) {
this.service = service;
}
public void updatedConfigurable(ConfigurableService service, Map<String, Object> properties) {
System.out.println("ConfigurableService updated");
}
public void welcome() {
service.execute();
}
}
如果我使用包含这些组件的 bundle 启动 OSGi 应用程序,我希望在执行 welcome
时最初,我将看到该组件已激活并且服务输出为空,因为尚未应用任何配置(确保这会在连续调用时发生变化)。如果我之后执行 configure Dirk
我期望用@Modified
注释的方法执行后表明服务配置已更新。我还期望updatedConfigurable
WelcomeCommand
中的方法被执行。至少这是我阅读规范后的理解。
现在我观察到 Equinox 和 Felix 的不同行为。
春分:
修改后的方法按预期调用,ConfigurableService
配置正确。但是updatedConfigurable(<Service>, <Map>)
不被调用。仅当我更改方法签名以采用 ServiceReference
时更新后的方法被调用。
规范规定所有引用事件方法都支持以下方法签名
void <method-name>(ServiceReference);
void <method-name>(<parameter-type>);
void <method-name>(<parameter-type>, Map);
我在规范中没有看到更新的方法是否有异常(exception),或者这是 Equinox 中的一个问题,我应该为此提出问题?
菲利克斯:
如果我在 Bndtools 中的 Felix 上运行相同的示例,则修改后的方法和更新方法都不会被调用。我检查了ConfigurationCommand
并且有可用的 ConfigurationAdmin,因此更新配置也不异常(exception)。但它从未以某种方式得到应用。
在 Felix 上运行示例时我是否遗漏了某些内容?
更新:
将控制台输出添加到每个生命周期事件方法会创建以下输出:
____________________________
Welcome to Apache Felix Gogo
g! ConfigurationCommand: Activate
ConfigurableService: Activate
WelcomeCommand: Activate
welcome
Service says: null
g! configure Dirk
g! welcome
Service says: null
g! exit 0
WelcomeCommand: Deactivate
ConfigurableService: Deactivate
ConfigurationCommand: Deactivate
如您所见,修改和更新事件永远不会被调用。
最佳答案
我认为问题在于 Gogo 命令的生命周期。
当命令未运行时,Gogo 不会保留服务对象。它跟踪 ServiceReference
,但在您实际调用 welcome
命令之前不会调用 getService
。因此,当您调用 welcome
时,WelcomeCommand
组件将被实例化,这会强制同时实例化 ConfigurableService
。
稍后,当welcome
命令完成时,WelcomeCommand
被释放,因此WelcomeCommand
和ConfigurableService
都将被释放GC 检测。因此,ConfigurableService
的任何实例都不会存在足够长的时间来接收 Modified 事件。
要解决此问题,请尝试使 WelcomeCommand
立即:
@Component(immediate = true, ...)
更新
通过电子邮件与 Dirk 进一步讨论后发现问题出在位置绑定(bind)。在配置管理中,配置默认“绑定(bind)”到创建它们的 bundle ,在本例中是包含 ConfigurationCommand
的 bundle 。一旦绑定(bind),它们就不能被另一个包使用,因此 ConfigurableService 永远不会看到配置。
要创建可由任何 bundle 使用的未绑定(bind)配置,请调用 ConfigAdmin.getConfiguration()
的双参数版本,并为第二个参数传递 null
。
关于java - 未调用 OSGi 修改事件方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36932825/