Osgi ConfigurationAdmin задержка при активации компонента - PullRequest
0 голосов
/ 06 декабря 2018

У меня есть служба, которая требует настройки

@Component(service=InstrumenterService.class ,configurationPid = "InstrumenterService", configurationPolicy = ConfigurationPolicy.REQUIRE, scope = ServiceScope.PROTOTYPE)
public class InstrumenterService

На эту службу ссылаются внутри другой службы:

@Component(service = SampleService.class, scope = ServiceScope.PROTOTYPE)
public class SampleService {

    @Reference(cardinality = ReferenceCardinality.OPTIONAL, scope = ReferenceScope.PROTOTYPE_REQUIRED, policyOption = ReferencePolicyOption.GREEDY)
    InstrumenterService coverageInstrumenter;

    public boolean hasInstrumenter() {
        if(coverageInstrumenter == null)
            return false;
        return true;
    }
}

Эта служба SampleService используется внутри класса Main, подключенного к основному osgiнить.Я использую ComponentServiceObjects, так как хочу создать SampleServices по требованию.

@Component(immediate = true, property = "main.thread=true")
public class Main implements Runnable {

    @Reference
    ConfigurationAdmin cfgAdm;

    @Reference(scope = ReferenceScope.PROTOTYPE_REQUIRED)
    private ComponentServiceObjects<SampleService> sampleServices;

    public void run() {
        if (cfgAdm != null) {
            Configuration configuration;
            try {
                configuration = cfgAdm.getConfiguration("InstrumenterService", "?");
                Hashtable<String, Object> props = new Hashtable<>();
                props.put("some_prop", "some_value");
                configuration.update(props);
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }

        SampleService servicess = sampleServices.getService();
        System.out.println(servicess.hasInstrumenter());
    }
}

Проблема, с которой я столкнулся, заключается в том, что конфигурация, заданная ConfigurationAdmin, не отображается в InstrumenterService, пока я не добавлю Thread.sleep (500);команда после вызова configuration.update.

Мне не очень удобно использовать команду Thread.sleep, чтобы убедиться, что обновление конфигурации видно.Есть ли API для проверки того, что конфигурация была обновлена ​​и доступна для использования?

Благодаря Нейлу я смог найти работоспособное решение.Я использовал ServiceTracker после того, как конфигурация была настроена на ожидание службы:

        BundleContext bundleContext = FrameworkUtil.getBundle(getClass()).getBundleContext();
    ServiceTracker serviceTracker = new ServiceTracker(bundleContext, InstrumenterService.class.getName(), null);

    serviceTracker.open();
    try {
        serviceTracker.waitForService(500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    serviceTracker.close();

Причина, по которой я прежде всего нуждался в ConfigurationAdmin, заключается в том, что существует интерфейс IInstrumenter, который может быть реализован многими различными классами.Имя этого инструментария задается в ConfigurationAdmin, а затем в других сервисах требуемая служба инструментария выбирается «автоматически».

Таким образом, любое количество инструментариев может быть добавлено в приложение, и только имядля того, чтобы его можно было использовать, необходимо знать инструментарий.

Хочу также отметить, что с помощью OSGI нам удалось разделить наше унаследованное монолитное приложение на несколько модулей (~ 15), и они не зависят напрямую отдруг друга, но используйте уровень API.

Еще раз спасибо за хорошую работу, которую вы делаете с OSGI.

1 Ответ

0 голосов
/ 11 декабря 2018

Как поясняется в комментариях, этот код не совсем реалистичен.В рабочем коде обычно не требуется обновлять запись конфигурации, а затем немедленно получать сервис, опубликованный компонентом.Это связано с тем, что любой такой код делает слишком много предположений о влиянии обновления конфигурации.

Вызов getServiceReference и getService возвращает только моментальный снимок состояния реестра службы в определенный момент времени.По своей природе ненадежно вызывать getService, ожидая, что он вернет значение.

В действительности мы всегда используем шаблон, в котором мы реагируем на получение уведомления о существовании службы.Это можно сделать различными способами, включая ServiceListener и ServiceTracker, но самое простое - написать компонент со ссылкой, например:

@Component
public class MyComponent {
    @Reference
    SampleService service;

    public void doSomething() {
        println(service.hasInstrumenter());
    }
}

Этот компонент имеет обязательную ссылку на SampleServiceи будет активирован только тогда, когда доступен экземпляр SampleService.

...