Порядок привязки декларативных сервисов OSGi с использованием политики STATIC - PullRequest
1 голос
/ 18 апреля 2019

Предположим, у меня есть нижеуказанный 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.

Как я могу это сделать?


Очень близкий вопрос (НО не тот же): Порядок привязки декларативных услуг OSGi


PS: я пытаюсь избежать ServiceTraker s и тому подобное.

Ответы [ 3 ]

2 голосов
/ 18 апреля 2019

Если вы используете bnd для генерации XML, то порядок основан на лексическом порядке ссылочного имени. То есть ссылки отсортированы по имени перед записью в XML.

Однако второе задание является динамическим. Я не совсем уверен, что вы можете положиться на заказ. Я мог бы предположить, что если новая служба войдет непосредственно перед тем, как SCR попытается внедрить администратора событий, который вызывает bindSomeInterface ранее. 1

Тем не менее, все это очень подробно описано в спецификации Декларативных услуг.

1 В оригинальных аннотациях, которые были разработаны в bnd до того, как OSGi их стандартизировала, я установил значение по умолчанию для MULTIPLE DYNAMIC, поскольку кажется, что не динамически, когда у вас есть несколько, очень опасно. Во время процесса стандартизации я, кажется, не смог убедить других участников в том, что MULTIPLE STATIC - действительно плохая комбинация, потому что результат не является детерминированным и может меняться при запуске.

2 голосов
/ 19 апреля 2019

В то время как вы можете контролировать порядок внедрения, используя либо лексическое упорядочение (как предложил Питер), либо упорядочивая элементы XML вручную, я бы рекомендовал не полагаться на это.

В вашем примере вы хотите отправить событие на EventAdmin, когда оба сервиса EventAdmin и SomeInterface связаны. Идеальное место для этого, наряду с любой другой необходимой инициализацией, - это метод активации компонента. Метод активации гарантированно будет вызван после того, как все статические ссылки связаны. В вашем случае количество элементов SomeInterface равно 0..n, поэтому его можно назвать нулевым много раз. Вы можете собрать все экземпляры в список и повторить этот список из метода активации.

Вам даже не нужно беспокоиться о том, чтобы сделать List потокобезопасным или использовать синхронизацию, потому что SCR гарантирует, что между последним связыванием службы и началом метода активации существует связь «произойдет до».

0 голосов
/ 18 апреля 2019

Простое изменение порядка тегов делает «трюк». 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-файле .

Что интересно, когда вы реализуете свой класс с использованием декларативных сервисов и не смотрите слишком много на xml-файл, сгенерированный IDE (в данном случае Eclipse), это может быть кошмаром, поскольку вы ожидаете, что сервисы будут разрешены в В том же порядке (последовательность строк кода в файле .java) вы объявили методы bind и unbind .

...