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 被释放,因此 WelcomeCommandConfigurableService 都将被 GC。因此,没有 ConfigurableService 的实例能够存活足够长的时间来接收 Modified 事件。

要解决这个问题,请尝试使 WelcomeCommand 立即:

@Component(immediate = true, ...)

更新

在通过电子邮件与德克进一步讨论后,发现问题出在位置绑定。在 Config Admin 中,配置默认 "bound" 到创建它们的包,在本例中是包含 ConfigurationCommand 的包。一旦绑定,它们就不能被另一个包使用,所以 ConfigurableService 永远看不到配置。

要创建可由任何包使用的未绑定配置,请调用 ConfigAdmin.getConfiguration() 的双参数版本并为第二个参数传递 null