【问题标题】:OSGi modify event method not called未调用 OSGi 修改事件方法
【发布时间】:2016-04-29 08:00:57
【问题描述】:

我正在使用 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(&lt;Service&gt;, &lt;Map&gt;) 没有被调用。只有当我将方法签名更改为采用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

如您所见,从不调用 modify 和 updated 事件。

【问题讨论】:

    标签: java osgi apache-felix equinox declarative-services


    【解决方案1】:

    我认为问题在于 Gogo 命令的生命周期。

    当命令未运行时,Gogo 不会保留服务对象。它跟踪ServiceReference,但在您实际调用welcome 命令之前不会调用getService。因此当你调用welcome时,WelcomeCommand组件将被实例化,这会在那个时候强制实例化ConfigurableService

    稍后当welcome 命令完成时,WelcomeCommand 被释放,因此WelcomeCommandConfigurableService 都将被GC'd。因此,ConfigurableService 的任何实例都不会存在足够长的时间来接收 Modified 事件。

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

    @Component(immediate = true, ...)
    

    更新

    在通过电子邮件与 Dirk 进一步讨论后,发现问题在于位置绑定。在 Config Admin 中,配置默认“绑定”到创建它们的包,在这种情况下,包包含 ConfigurationCommand。一旦绑定它们就不能被另一个捆绑包使用,因此ConfigurableService 永远不会看到配置。

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

    【讨论】:

    • 您能否检查(使用scr:listscr:info 命令)ConfigurableService 是否实际存在并且存在实例。另外请去掉unbind="-" 的东西,它不是必需的,我不知道它可能有什么副作用。
    • 我删除了unbind="-" 属性。我刚刚添加它是因为规范说需要明确说明没有取消绑定方法。 Neon 中新的 DS 注释支持会抱怨。对于 Felix,我搬到了 Bndtools 并且缺少 unbind 方法没有问题。尽管如此,它并没有改变任何东西。使用scr:listscr:info 表明ConfigurableService 处于活动状态(State: active)。对我来说,一切看起来都很好。我应该寻找什么特别的东西吗?
    • 规范中根本没有这样说,因此需要修复 Neon 中的 DS 注释支持。如果存在与推断的 unbind 方法名称冲突的方法,您只需要说 unbind="-"。 IE。您有一个名为 unsetConfigAdmin 的方法,但您不希望将其用作 setConfigAdmin 的取消绑定方法。
    • 关于剩余的生命周期问题......在这个距离上调试变得越来越棘手。也许如果您将打印语句放在每个绑定/取消绑定/更新方法和激活/停用方法中,然后将输出转储到这里?
    • 对不起,这不是规范,而是@Reference 的Javadoc 说要声明没有取消绑定方法,必须使用值{@code "-"}。 。我在每个方法中添加了控制台输出,并将 ConfigureCommand 配置为立即启动。出于格式原因,我在原始问题中添加了输出。
    猜你喜欢
    • 1970-01-01
    • 2018-04-13
    • 1970-01-01
    • 2013-03-27
    • 2014-09-18
    • 1970-01-01
    • 2015-04-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多