【问题标题】:Bind order of OSGi declarative services using STATIC policy使用 STATIC 策略绑定 OSGi 声明式服务的顺序
【发布时间】:2019-04-18 13:26:53
【问题描述】:

假设我有以下 OSGi 组件,它应该在每次在运行时注册 SomeInterface 的新实现时发送一个事件。

为此,我将EventAdmin 绑定到eventAdmin 变量中,然后在bindSomeInterface 方法中使用它。

import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;

@Component
public class Sender {

    private EventAdmin eventAdmin;

    @Reference
    public void bindEventAdmin(EventAdmin eventAdmin) {
        this.eventAdmin = eventAdmin;
    }

    public void unbindEventAdmin(EventAdmin eventAdmin) {
        this.eventAdmin = null;
    }

    @Reference(cardinality = ReferenceCardinality.MULTIPLE)
    public void bindSomeInterface(SomeInterface instance) {

       // var prop create here... (non relevant code)
        Event event = new Event("topic", prop);

       // it is NULL!
        eventAdmin.sendEvent(event);
    }

    public void unbindSomeInterface(SomeInterface instance) {

    }

}

生成的xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="com.package.Sender">
   <reference bind="bindSomeInterface" cardinality="0..n" interface="com.package.bindSomeInterface" name="SomeInterface" policy="static" unbind="unbindSomeInterface"/>
   <reference bind="bindEventAdmin" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static" unbind="unbindEventAdmin"/>
   <implementation class="com.package.Sender"/>
</scr:component>

问题

bindSomeInterface 首先被调用(得到一个“通知”,SomeInterface 的新实例已在运行时注册),然后bindEventAdmin 被调用。这不是我们想要的效果。

预期行为

我想先绑定EventAdmin 实例,然后绑定SomeInterface 实例。

我该怎么做?


非常接近的问题(但不一样):Bind order of OSGi declarative services


PS:我试图避免ServiceTrakers 之类的东西。

【问题讨论】:

    标签: osgi declarative-services


    【解决方案1】:

    虽然您可以使用词法排序(如 Peter 所建议的)或手动排序 XML 元素来控制注入顺序,但我建议不要依赖它。

    在您的示例中,当EventAdmin 和SomeInterface 服务都绑定时,您希望向EventAdmin 发送事件。执行此操作以及任何其他必需的初始化的最佳位置是在组件的 activate 方法中。 activate 方法保证在 all 静态引用被绑定后被调用。在您的情况下,SomeInterface 的基数是0..n,因此它可能被称为零到多次。您可以将所有实例累积到一个 List 中,并从 activate 方法中迭代该列表。

    您甚至不必担心使 List 线程安全或使用同步,因为 SCR 确保在最后一个服务绑定和 activate 方法的开始之间存在“先发生”关系。

    【讨论】:

      【解决方案2】:

      如果您使用 bnd 生成 XML,则顺序基于引用名称的词法顺序。 IE。引用在写入 XML 之前按名称排序。

      但是,第二个引用是动态的。我不确定您是否可以依赖订单。我可以设想,如果在 SCR 尝试注入之前调用 bindSomeInterface 的事件管理员之前有新服务进入。 1

      也就是说,这一切都在声明式服务规范中进行了详细概述。

      1 在 OSGi 标准化之前在 bnd 中开发的原始注释中,我将 MULTIPLE DYNAMIC 设为默认值,因为当你有多。在标准化过程中,我似乎无法让其他成员相信 MULTIPLE STATIC 是一个非常糟糕的组合,因为结果不是确定性的,并且每次启动都会改变。

      【讨论】:

      • 您说得对,您指定的引用是静态的,因为这是默认值,更改基数不会影响策略。
      【解决方案3】:

      只需更改标签顺序即可“绝招”。 xml 文件现在如下所示:

      <?xml version="1.0" encoding="UTF-8"?>
      <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" name="com.package.Sender">
         <reference bind="bindEventAdmin" interface="org.osgi.service.event.EventAdmin" name="EventAdmin" policy="static" unbind="unbindEventAdmin"/>
         <reference bind="bindSomeInterface" cardinality="0..n" interface="com.package.bindSomeInterface" name="SomeInterface" policy="static" unbind="unbindSomeInterface"/>
         <implementation class="com.package.Sender"/>
      </scr:component>
      

      显然框架会尝试按照它们在 xml 文件中声明的相同顺序解析所有引用。

      有趣的是,当您使用声明式服务实现您的类并且不要过多查看 IDE(在本例中为 Eclipse)生成的 xml 文件时,这可能是一场噩梦,因为您希望服务在与您声明 bind 和 unbind 方法的顺序相同(.java 文件中的代码行序列)。

      【讨论】:

      • 是的,这可能是一场噩梦......所以不要依赖服务注入命令!在激活方法中进行初始化。请参阅我对此的单独回答。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-10-14
      • 1970-01-01
      • 2012-04-27
      • 2010-09-23
      • 1970-01-01
      • 2018-05-20
      • 2011-11-16
      相关资源
      最近更新 更多