OSGi 修改事件方法未调用
OSGi modify event method not called
我正在研究 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);
}
}
最后我创建了另一个使用 ConfigurableService
的 Felix Gogo shell 命令组件
@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();
}
}
如果我使用包含这些组件的包启动 OSGi 应用程序,我希望在最初执行 welcome
时,我会看到组件被激活并且服务输出为空,因为没有应用任何配置但是(确保这会在连续调用时发生变化)。如果我之后执行 configure Dirk
我希望执行带有 @Modified
注释的方法以指示服务配置已更新。我还希望执行 WelcomeCommand
中的 updatedConfigurable
方法。至少这是我阅读规范的理解。
现在我观察到 Equinox 和 Felix 中的不同行为。
春分点:
修改后的方法按预期调用并且 ConfigurableService
配置正确。但是 updatedConfigurable(<Service>, <Map>)
没有被调用。只有当我更改方法签名以采用 ServiceReference
时,更新的方法才会被调用。
规范说所有引用事件方法都支持以下方法签名
void <method-name>(ServiceReference);
void <method-name>(<parameter-type>);
void <method-name>(<parameter-type>, Map);
我在规范中没有看到更新后的方法是否有例外,或者这是 Equinox 中的一个问题,我应该为此提出问题?
菲利克斯:
如果我 运行 在 Bndtools 的 Felix 上使用相同的示例,则既不会调用修改的方法也不会调用更新的方法。我检查了 ConfigurationCommand
并且有可用的 ConfigurationAdmin,因此更新配置时没有异常。但它从未以某种方式应用。
我是否遗漏了 运行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, ...)
更新
在通过电子邮件与德克进一步讨论后,发现问题出在位置绑定。在 Config Admin 中,配置默认 "bound" 到创建它们的包,在本例中是包含 ConfigurationCommand
的包。一旦绑定,它们就不能被另一个包使用,所以 ConfigurableService
永远看不到配置。
要创建可由任何包使用的未绑定配置,请调用 ConfigAdmin.getConfiguration()
的双参数版本并为第二个参数传递 null
。
我正在研究 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);
}
}
最后我创建了另一个使用 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();
}
}
如果我使用包含这些组件的包启动 OSGi 应用程序,我希望在最初执行 welcome
时,我会看到组件被激活并且服务输出为空,因为没有应用任何配置但是(确保这会在连续调用时发生变化)。如果我之后执行 configure Dirk
我希望执行带有 @Modified
注释的方法以指示服务配置已更新。我还希望执行 WelcomeCommand
中的 updatedConfigurable
方法。至少这是我阅读规范的理解。
现在我观察到 Equinox 和 Felix 中的不同行为。
春分点:
修改后的方法按预期调用并且 ConfigurableService
配置正确。但是 updatedConfigurable(<Service>, <Map>)
没有被调用。只有当我更改方法签名以采用 ServiceReference
时,更新的方法才会被调用。
规范说所有引用事件方法都支持以下方法签名
void <method-name>(ServiceReference);
void <method-name>(<parameter-type>);
void <method-name>(<parameter-type>, Map);
我在规范中没有看到更新后的方法是否有例外,或者这是 Equinox 中的一个问题,我应该为此提出问题?
菲利克斯:
如果我 运行 在 Bndtools 的 Felix 上使用相同的示例,则既不会调用修改的方法也不会调用更新的方法。我检查了 ConfigurationCommand
并且有可用的 ConfigurationAdmin,因此更新配置时没有异常。但它从未以某种方式应用。
我是否遗漏了 运行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, ...)
更新
在通过电子邮件与德克进一步讨论后,发现问题出在位置绑定。在 Config Admin 中,配置默认 "bound" 到创建它们的包,在本例中是包含 ConfigurationCommand
的包。一旦绑定,它们就不能被另一个包使用,所以 ConfigurableService
永远看不到配置。
要创建可由任何包使用的未绑定配置,请调用 ConfigAdmin.getConfiguration()
的双参数版本并为第二个参数传递 null
。