使用 STATIC 策略绑定 OSGi 声明性服务的顺序
Bind order of OSGi declarative services using STATIC policy
假设我有下面的 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
首先被调用(得到 "notification" SomeInterface
的新实例在 运行 时间注册)然后 bindEventAdmin
被调用。这不是想要的效果。
预期行为
我想先绑定 EventAdmin
个实例,然后再绑定 SomeInterface
个实例。
我该怎么做?
非常接近的问题(但不一样):Bind order of OSGi declarative services
PS:我正在努力避免 ServiceTraker
之类的东西。
只需更改标签顺序即可 "trick"。 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文件.
中声明的相同顺序解析所有引用
有趣的是,当您使用声明性服务实现 class 并且不要过多查看 IDE 生成的 xml 文件(本例中为 Eclipse)这可能是一场噩梦,因为您希望服务以与声明 bind 和 解除绑定 方法。
如果您使用 bnd 生成 XML,则该顺序基于引用名称的词法顺序。 IE。引用在写入 XML.
之前按名称排序
但是,第二个引用是动态的。我不确定您是否可以相信订单。我可以设想,如果在 SCR 尝试注入之前调用 bindSomeInterface
的 Event Admin 之前出现新服务。 1
也就是说,声明式服务规范中概述了所有详细信息。
1 在 OSGi 标准化之前在 bnd 中开发的原始注释中,我将 MULTIPLE DYNAMIC 默认设置为 MULTIPLE DYNAMIC 因为它看起来非常危险 not 当你有多个时要动态。在标准化过程中,我似乎无法说服其他成员 MULTIPLE STATIC 是一个非常糟糕的组合,因为结果不是确定性的,每次启动都会改变。
虽然您可以使用词法排序(如 Peter 所建议的)或通过手动排序 XML 元素来控制注入顺序,但我建议不要依赖关于这个。
在您的示例中,当 EventAdmin
和 SomeInterface
服务都已绑定时,您希望向 EventAdmin
发送一个事件。执行此操作以及任何其他所需初始化的最佳位置是在组件的 activate 方法中。保证在 all 静态引用绑定后调用 activate 方法。在您的情况下, SomeInterface
的基数是 0..n
因此它可能被称为零次到多次。您可以将所有实例累积到一个列表中,并从激活方法迭代该列表。
您甚至不必担心使 List 线程安全或使用同步,因为 SCR 确保在最后一个服务绑定和激活方法的开始之间存在 "happens-before" 关系。
假设我有下面的 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
首先被调用(得到 "notification" SomeInterface
的新实例在 运行 时间注册)然后 bindEventAdmin
被调用。这不是想要的效果。
预期行为
我想先绑定 EventAdmin
个实例,然后再绑定 SomeInterface
个实例。
我该怎么做?
非常接近的问题(但不一样):Bind order of OSGi declarative services
PS:我正在努力避免 ServiceTraker
之类的东西。
只需更改标签顺序即可 "trick"。 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文件.
中声明的相同顺序解析所有引用有趣的是,当您使用声明性服务实现 class 并且不要过多查看 IDE 生成的 xml 文件(本例中为 Eclipse)这可能是一场噩梦,因为您希望服务以与声明 bind 和 解除绑定 方法。
如果您使用 bnd 生成 XML,则该顺序基于引用名称的词法顺序。 IE。引用在写入 XML.
之前按名称排序但是,第二个引用是动态的。我不确定您是否可以相信订单。我可以设想,如果在 SCR 尝试注入之前调用 1bindSomeInterface
的 Event Admin 之前出现新服务。
也就是说,声明式服务规范中概述了所有详细信息。
1 在 OSGi 标准化之前在 bnd 中开发的原始注释中,我将 MULTIPLE DYNAMIC 默认设置为 MULTIPLE DYNAMIC 因为它看起来非常危险 not 当你有多个时要动态。在标准化过程中,我似乎无法说服其他成员 MULTIPLE STATIC 是一个非常糟糕的组合,因为结果不是确定性的,每次启动都会改变。
虽然您可以使用词法排序(如 Peter 所建议的)或通过手动排序 XML 元素来控制注入顺序,但我建议不要依赖关于这个。
在您的示例中,当 EventAdmin
和 SomeInterface
服务都已绑定时,您希望向 EventAdmin
发送一个事件。执行此操作以及任何其他所需初始化的最佳位置是在组件的 activate 方法中。保证在 all 静态引用绑定后调用 activate 方法。在您的情况下, SomeInterface
的基数是 0..n
因此它可能被称为零次到多次。您可以将所有实例累积到一个列表中,并从激活方法迭代该列表。
您甚至不必担心使 List 线程安全或使用同步,因为 SCR 确保在最后一个服务绑定和激活方法的开始之间存在 "happens-before" 关系。