Декларативные сервисы OSGI (DS):Каков хороший способ использования экземпляров компонентов сервиса

StackOverflow https://stackoverflow.com/questions/1102754

Вопрос

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

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

Пока все работает нормально, и 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.Создайте какой-нибудь Реестр где каждый компонент регистрируется сразу же после вызова метода activate().

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 в Активаторе, но я думал, что это было бы возможно и без него.

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

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

Спасибо Кристоф


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

Спасибо, что разъяснили этот вопрос относительно оригинальной версии, но я думаю, вам все равно нужно указать, почему третий класс не может быть создан с помощью чего-то вроде 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, но предполагается, что это какой-то псевдокод :)

Спасибо Кристоф

Это было полезно?

Решение

Кристоф,

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

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

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

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

Я надеюсь, что это поможет.

С уважением, Нил

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

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

Другие советы

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

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

Тогда вы сможете вызвать его отовсюду:Активатор.getDefault().getWhateverService()

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top