Декларативные службы (DS) OSGI: Как правильно использовать экземпляры компонентов служб - PullRequest
5 голосов
/ 09 июля 2009

Я только начинаю работать с OSGI и декларативными службами (DS), использующими Equinox и Eclipse PDE.

У меня есть 2 Связки, A и B. Пакет A предоставляет компонент, который используется Пакетом B. Оба пакета также снова предоставляют этот сервис реестру OSGI Service.

Пока все работает нормально, и Equinox соединяет компоненты вместе, что означает, что Bundle A и Bundle B создаются в Equinox (вызывая конструктор по умолчанию), а затем соединение происходит с использованием методов bind / unbind.

Теперь, когда Equinox создает экземпляры этих компонентов / сервисов, я хотел бы знать, как лучше всего получить этот экземпляр?

Итак, предположим, что существует третий класс класс, который НЕ создан OSGI:

Class WantsToUseComponentB{
public void doSomethingWithComponentB(){
 // how do I get componentB??? Something like this maybe?
 ComponentB component = (ComponentB)someComponentRegistry.getComponent(ComponentB.class.getName());
}

Я вижу следующие варианты прямо сейчас:



1. Используйте ServiceTracker в Активаторе , чтобы получить Службу ComponentBundleA.class.getName () (я уже пробовал это, и это работает, но мне кажется, что это накладные расходы) и сделать его доступным через статические фабричные методы

 
public class Activator{

   private static ServiceTracker componentBServiceTracker;   

   public void start(BundleContext context){

     componentBServiceTracker = new ServiceTracker(context, ComponentB.class.getName(),null);
   }

   public static ComponentB getComponentB(){
     return (ComponentB)componentBServiceTracker.getService(); 
   };

}

2. Создайте какой-нибудь реестр , в котором каждый компонент регистрируется сразу после вызова метода activ ().

public ComponentB{

public void bind(ComponentA componentA){
   someRegistry.registerComponent(this);
}

или

public ComponentB{

   public void activate(ComponentContext context){
      someRegistry.registerComponent(this);
   }

}

}

3. Использовать существующий реестр внутри osgi / equinox , который имеет эти экземпляры? Я имею в виду, что OSGI уже создает экземпляры и связывает их вместе, поэтому объекты уже где-то есть. Но где? Как я могу получить их?

Заключение Откуда класс WantsToUseComponentB (который НЕ является Компонентом и НЕ создан OSGI) получает экземпляр ComponentB? Есть ли какие-либо модели или лучшие практики? Как я уже сказал, мне удалось использовать ServiceTracker в Activator, но я думал, что это было бы возможно без него.

То, что я ищу, на самом деле напоминает BeanContainer из Springframework, где я могу просто сказать что-то вроде Container.getBean (ComponentA.BEAN_NAME). Но я не хочу использовать Spring DS.

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

Спасибо Christoph

<ч />

ОБНОВЛЕНИЕ: Ответ на комментарий Нила:

Спасибо за разъяснение этого вопроса по сравнению с оригинальной версией, но я думаю, что вам все еще нужно указать, почему третий класс не может быть создан с помощью чего-то вроде DS.

Хм, не знаю. Может быть, есть способ, но мне нужно было бы реорганизовать всю мою платформу, чтобы она основывалась на DS, чтобы больше не было операторов "new MyThirdClass (arg1, arg2)". Не знаю, как это сделать, но я читал кое-что о ComponentFactories в DS. Так что вместо того, чтобы делать

MyThirdClass object = new MyThirdClass(arg1, arg2);

Я мог бы сделать

ComponentFactory myThirdClassFactory = myThirdClassServiceTracker.getService(); // returns a 

if (myThirdClassFactory != null){
  MyThirdClass object = objectFactory.newInstance();

   object.setArg1("arg1");
  object.setArg2("arg2");
}
else{
 // here I can assume that some service of ComponentA or B went away so MyThirdClass Componenent cannot be created as there are missing dependencies?

}

На момент написания статьи я не знаю точно, как использовать ComponentFactories, но предполагается, что это какой-то псевдокод:)

Спасибо Christoph

Ответы [ 3 ]

7 голосов
/ 09 июля 2009

Christoph,

Спасибо за разъяснение этого вопроса по сравнению с оригинальной версией, но я думаю, что вам все еще нужно указать, почему третий класс не может быть создан с помощью чего-то вроде DS.

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

Если вам действительно нужен доступ к сервису без использования DS или чего-то в этом роде (и существует множество «подобных вещей», например Spring-DM, iPOJO, Guice / Peaberry и т. Д.), То вам следует использовать ServiceTracker. Я согласен, что есть много накладных расходов - опять же, именно поэтому вместо этого существует DS.

Чтобы ответить на ваше предложение № (2), нет, вам не следует создавать собственный реестр служб, поскольку реестр служб уже существует. Если бы вы создали отдельный параллельный реестр, вам все равно пришлось бы обрабатывать всю динамику, но вам пришлось бы обрабатывать его в двух местах вместо одного. То же относится и к предложению (3).

Надеюсь, это поможет.

С уважением, Neil

ОБНОВЛЕНО: Между прочим, хотя у Spring есть бэкдор Container.getBean (), вы замечаете, что во всей документации Spring настоятельно рекомендуется не использовать этот бэкдор: чтобы получить бин Spring, просто создайте другой бин, который ссылается на него , То же самое относится и к DS, то есть лучший способ завладеть компонентом DS - это создать другой компонент DS.

Также обратите внимание, что в мире OSGi, даже если вы используете Spring-DM, нет простого способа просто вызвать getBean (), потому что сначала вам нужно овладеть Spring ApplicationContext. Это сама служба OSGi, так как вы можете получить эту службу?

1 голос
/ 09 июля 2009

Christoph, Не знаю, действительно ли я понимаю твою проблему. за экс. Пакет A предоставляет сервис с использованием компонента DS:

<service>
  <provide interface="org.redview.lnf.services.IRedviewLnfSelectedService"/>

Пакет B требует эту услугу с использованием компонента DS:

<implementation class="ekke.xyz.rcp.application.internal.XyzApplicationLnfComponent"/>

как только Пакет A предоставляет Сервис, Пакет B "получает" его через метод bind () класса реализации:

public class XyzApplicationLnfComponent {
public void bind(IRedviewLnfSelectedService lnfSelectedService) {
    // here it is
}

надеюсь, это поможет Ekke

0 голосов
/ 11 мая 2010

Простой способ: добавить компонент DS в класс Activator с помощью Riena: http://wiki.eclipse.org/Riena_Getting_Started_with_injecting_services_and_extensions

Тогда вы можете вызывать его откуда угодно: Activator.getDefault (). GetWhwhatService ()

...