Как правильно использовать OSGi getServiceReference () - PullRequest
2 голосов
/ 28 апреля 2010

Я новичок в OSGi и наткнулся на несколько примеров об услугах OSGi.

Например:

import org.osgi.framework.*;
import org.osgi.service.log.*;

public class MyActivator implements BundleActivator {
  public void start(BundleContext context) throws Exception {
    ServiceReference logRef = 
      context.getServiceReference(LogService.class.getName());
  }
}

У меня вопрос, почему вы используете

getServiceReference(LogService.class.getName())

вместо

getServiceReference("LogService")

Если вы используете LogService.class.getName () , вам необходимо импортировать интерфейс. Это также означает, что вам необходимо импортировать пакет org.osgi.services.log в ваш файл MANIFEST.MF.

Разве это не является абсолютно контрпродуктивным, если вы хотите уменьшить зависимости, чтобы вызвать слабую связь? Насколько я знаю, одним из преимуществ сервисов является то, что потребитель сервиса не должен знать издателя сервиса. Но если вам нужно импортировать один конкретный интерфейс, вы должны четко знать, кто его предоставляет. Используя только такую ​​строку, как «LogService», вам не нужно знать, что интерфейс предоставляется org.osgi.services.log.LogService .

Что мне здесь не хватает?

Ответы [ 4 ]

6 голосов
/ 28 апреля 2010

Похоже, вы перепутали реализацию и интерфейс

Использование фактического интерфейса для имени (и импорт интерфейса, который вы в конечном итоге будете выполнять) укрепляет контракт интерфейса, на который рассчитаны сервисы. Вы не заботитесь о реализации LogService, но вы заботитесь об интерфейсе. Каждый LogService должен будет реализовывать один и тот же интерфейс, следовательно, вы используете интерфейс для получения сервиса. Насколько вам известно, LogService действительно является оболочкой для SLF4J, предоставляемой другим пакетом. Все, что вы видите, это интерфейс. Это слабая связь, которую вы ищете. Вам не нужно поставлять интерфейс с каждой реализацией. Оставьте интерфейс в своем собственном комплекте и имейте несколько реализаций этого интерфейса.

Примечание: ServiceTracker обычно проще в использовании, попробуйте!

Дополнительные преимущества: использование интерфейса позволяет получить имя класса, избегает орфографических ошибок, чрезмерных строковых литералов и значительно упрощает рефакторинг.

После того, как вы получите ServiceReference, ваша следующая пара строк, вероятно, будет включать это:

Object logSvc = content.getService(logRef)

// What can you do with logSvc now?!? It's an object, mostly useless

// Cast to the interface ... YES! Now you need to import it!
LogSerivce logger = (LogService)logSvc;

logger.log(LogService.LOG_INFO, "Interfaces are a contract between implementation and consumer/user");
3 голосов
/ 29 апреля 2010

Если вы используете LogService, вы все равно будете с ним связаны. Если вы пишете промежуточное программное обеспечение, вы, вероятно, получите параметризованное имя через какой-нибудь XML-файл или через API. И да, «LogService» ужасно потерпит неудачу, вам нужно использовать полное имя: «org.osgi.service.log.LogService». Основной причиной использования шаблона LogService.class.getName () является правильное переименование при рефакторинге кода и минимизация орфографических ошибок. Следующий OSGi API, скорее всего, будет иметь:

ServiceReference<S> getServiceReference(Class<S> type)

призывает повысить безопасность типов.

В любом случае, я бы никогда не использовал эти низкоуровневые API, если бы вы не разрабатывали промежуточное программное обеспечение. Если вы действительно зависите от конкретного класса, то DS бесконечно проще, и даже больше, когда вы используете его с аннотациями bnd (http://enroute.osgi.org/doc/217-ds.html).

@Component
class Xyz implements SomeService {
  LogService log;

  @Reference
  void setLog( LogService log) { this.log = log; }

  public void foo() { ... someservice ... }

}

Если вы разрабатываете промежуточное программное обеспечение, вы получаете классы обслуживания, как правило, не зная фактического класса, через строку или объект класса. В этих случаях используется OSGi API, основанный на строках, потому что он позволяет нам быть более ленивым, не создавая загрузчик классов до последнего момента времени. Я думаю, что самая большая ошибка, которую мы сделали в OSGi 12 лет назад, заключается в том, чтобы не включать концепции DS в ядро ​​...: - (

1 голос
/ 29 апреля 2010

Вы не можете использовать значение "LogService" в качестве имени класса, чтобы получить ServiceReference, потому что вы должны использовать полное имя класса "org.osgi.services.log.LogService".

Если вы импортируете пакет таким образом: org.osgi.services.log;resolution:=optional и вы используете ServiceTracker для отслеживания сервисов в методе BundleActivator.start (), я предлагаю использовать "org.osgi.services.log.LogService" вместо LogService.class.getName() при инициализации ServiceTracker. В этом случае вы не получите NoClassDefFoundError/ClassNotFountException при запуске пакета.

0 голосов
/ 29 апреля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...