Статьи

CompletableFuture для OSGi Remote Services

Как некоторые из вас могут знать, реализация  ECF OSGi Remote Services поддерживает  асинхронные прокси . Это позволяет потребителям удаленных сервисов легко использовать асинхронный / неблокирующий вызов для доступа к удаленному сервису. Например … вот простой интерфейс службы, который используется в нашем  руководстве по удаленной службе :

public interface ITimeService {
    public Long getCurrentTime();
}

Как и в случае любой удаленной службы OSGi, любой потребитель, обнаруживший эту службу, потенциально заблокируется, когда он вызовет getCurrentTime (). Это просто природа семантики вызова / возврата, применяемой к удаленному взаимодействию … и так будет справедливо для любой реализации удаленных сервисов OSGi. 

Подразделение ECF OSGi Remote Service предлагает асинхронные прокси, что означает, что если определен соответствующий интерфейс службы … например 

public interface ITimeServiceAsync {
    public Future getCurrentTimeAsync();
}

тогда потребители смогут использовать ITimeServiceAsync для доступа к услуге … например: 

ITimeServiceAsync tsa = ... get ITimeServiceAsync reference

Future timeFuture = tsa.getCurrentTimeAsync();
...do work...
Long time = timeFuture.get();

В  ECF 3.8.0  мы дополнительно добавили [3] … то есть возможность автоматически регистрировать ITimeServiceAsync в качестве службы на потребителе … так что (например) ссылка ITimeServiceAsync может быть введена через декларативные службы … например 

...ds component impl...

void bindTimeServiceAsync(ITimeServiceAsync tsa) {
     ...use or store tsa...
}

Это [3] доступно в ECF 3.8.0. Обратите внимание, что сервисные интерфейсы не имеют абсолютно никакой ссылки ни на классы ECF, ни на классы OSGi. Ничего не нужно сейчас. 

Как многие из вас наверняка знают … java8 только что вышел, и большая часть java8 — это улучшенная поддержка параллелизма, функционального программирования и лямбд. Эта поддержка параллелизма в java8 потенциально очень полезна для пользователей OSGi Remote Services. 

Рассмотрим CompletableFuture, который, как следует из названия, является типом java.util.concurrent.Future. У него есть несколько очень хороших свойств для дизайнеров API / сервисов … главное в том, что совсем нет необходимости напрямую вызывать Future.get … но вы можете написать хороший, лаконичный и * гарантированно неблокирующий, но асинхронное * использование, такое как: 

CompletableFuture cf = ...get CompletableFuture....

cf.thenAccept((time) -> System.out.println("time is: " + time));

Это хорошо … это совершенно не блокирует … и очень лаконично. Также вы можете делать очень интересные вещи с асинхронной / управляемой событиями цепочкой / фильтрацией и т. Д. И т. Д. Все гарантированно не блокируется … что является ключевой гарантией удаленного взаимодействия. 

Вчера я понял, что с Java8 наши асинхронные прокси могут быть легко обобщены, чтобы сделать это: 

public interface ITimeServiceAsync {
    public CompletableFuture getCurrentTimeAsync();
}

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

...service component impl...
void bindTimeServiceAsync(ITimeServiceAsync tsa) {
       // Get the CompletableFuture...no blocking here
       CompletableFuture cf = tsa.getCurrentTimeAsync();
       // print out time when done...no blocking anywhere!
       cf.thenAccept((time) -> System.out.println("Remote time is: " + time));
}

Обратите внимание на несколько вещей: 

  1. Там нет блокировки нигде. Это верно, хотя фактическое значение времени извлекается через удаленный сервис OSGi
  2. Хост удаленного сервиса не должен предоставлять какую-либо реализацию ITimeServiceAsync. Он построен RS ECL автоматически
  3. Очень легко справиться со сбоем (например, сбой сети / io) через CompletableFuture.handle. Это, очевидно, большая проблема для удаленных служб … которые гораздо более склонны к сбою из-за сети.
  4. Нет ссылки ни на классы OSGi, ни на классы ECF в коде хоста или потребителя.

Это хорошо для пользователей удаленных сервисов, потому что они не дают им надежных гарантий блокировки и могут быть очень эффективно реализованы (без дополнительных потоков) удаленными поставщиками услуг, использующими асинхронный обмен сообщениями (например, JMS и т. Д.). Это также позволяет им использовать все API-интерфейсы CompletableFuture (см.  Javadoc CompletableFuture ).

Это, очевидно, будет частью ECF  Luna … и я создал некоторый тестовый код (как выше), который я собираюсь использовать для создания другого учебника в следующем месяце. Посмотрите  вики ECF  для этого урока. 

Единственный недостаток состоит в том, что это, конечно, зависит от Java8 … и поэтому требует, чтобы и удаленный хост-сервис, и потребитель использовали Java8, и чтобы поставщик распространения был немного расширен для использования CompletableFuture. К счастью, технически не сложно сделать эти улучшения, и мы сделаем классы поддержки доступными для тех, кто желает, чтобы Java8 улучшала существующего или своего собственного провайдера RS. 

[1]  https://wiki.eclipse.org/ECF/Asynchronous_Remote_Services
[2] https://wiki.eclipse.org/Tutorial:_Building_your_first_OSGi_Remote_Service
[3]  https://bugs.eclipse.org/buug/sho_ ? ID = 420785