Как использовать 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.