Как использовать OSGi сервис из OSGi HTTP Service

У меня есть пакет A, который предоставляет следующий сервис:

В OSGI-INF/config.xml

<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" 
    name="com.example.MyService" modified="updated" immediate="true">
 <implementation class="com.example.impl.MyServiceImpl"/>
 <service>
  <provide interface="com.example.MyService"/>
 </service>
</scr:component>

Следующим шагом я хочу использовать этот сервис из сервлета в комплекте B.

Я делаю следующее:

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
 BundleContext bundleContext = (BundleContext) getServletContext().getAttribute("osgi-bundlecontext");
    if (bundleContext != null) {
     // Here MyService is the service exposed as declarative service
     MyService myService = getService(bundleContext, MyService.class);
     if(myService != null) {
      // I want to invoke some method declared in MyService interface
      myService.invokeMyServiceMethod();
     }
    }
}// end of doPost

protected <T> T getService(BundleContext bundleContext, Class<T> type) {
    ServiceReference<T> serviceRef = bundleContext.getServiceReference(type);
    if (serviceRef == null) {
        return null;
    }
    T service = bundleContext.getService(serviceRef);
    return service;
}// end of getService method

Когда сервисы в OSGi приходят и уходят, правильно ли предположить, что даже если проверка на ненулевую ссылку в методе doPost проходит, следующий оператор myService.invokeMyServiceMethod() не будет генерировать NPE?

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

Если это неправильный способ получения ссылки на службу от службы Http, то какой правильный?

Я использую Equinox в качестве реализации OSGi.

Ура, Борис

1 ответ

Я думаю, что вы пропустили несколько битов декларативных сервисов (DS):-) Вся идея DS в том, что вы указываете свои зависимости в XML (или НАМНОГО лучше с аннотациями). Вот как должен выглядеть сервлет:

@Component(provide=Servlet.class)
public class MyServlet extends HttpServlet {
  T myService;

  protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException {
    myService.invokeMyServiceMethod();
  }

  @Reference
  T setT(T t) {
    myService =t;
  }
}

Единственное, что требуется, это убедиться, что у вас установлен пакет Http Whiteboard от Apache Felix (да, он отлично работает на Equinox, прелесть стандартов). Этот пакет отслеживает все зарегистрированные службы Servlet и добавляет их в службу Http. Так как DS гарантирует, что ваш компонент не зарегистрирован, пока он не имеет myService, ваш myService гарантированно не будет нулевым. Это называется статическим режимом DS: все ваши зависимости удовлетворяются до того, как вам позвонят.

Если вы смелый, вы могли бы объявить setT метод быть динамичным. Тогда ваш компонент будет зарегистрирован, даже если T-сервис отсутствует. Например, позволяет сообщать вызывающему абоненту, что услуга отсутствует. Это называется динамическим режимом.

Используемые аннотации являются стандартными DS. Они обрабатываются bnd и превращаются в XML. Это работает в maven, gradle и т. Д., Но лучше всего, конечно, в bndtools.

Другие вопросы по тегам