Рубрики
Без рубрики

Введение в финал

Узнайте, как отправлять и получать информацию по проводам с помощью библиотеки RPC Twitter Finagle.

Автор оригинала: baeldung.

1. Обзор

В этом уроке мы быстро рассмотрим Finagle, библиотеку RPC Twitter.

Мы будем использовать его для создания простого клиента и сервера.

2. Строительные блоки

Прежде чем мы углубимся в реализацию, нам нужно ознакомиться с основными концепциями, которые мы будем использовать для создания нашего приложения. Они широко известны, но могут иметь несколько иное значение в мире Финагла.

2.1. Услуги

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

2.2. Фильтры

Фильтры также являются функциями. Они принимают запрос и службу, выполняют некоторые операции с запросом, передают его службе, выполняют некоторые операции с результирующим Будущим и , наконец, возвращают окончательный Будущее . Мы можем думать о них как о аспектах , поскольку они могут реализовывать логику, которая происходит вокруг выполнения функции, и изменять ее вход и выход.

2.3. Фьючерсы

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

3. Обслуживание

Во-первых, мы реализуем простую службу приветствия HTTP. Он возьмет параметр name из запроса, ответит и добавит обычное сообщение “Привет”.

Для этого нам нужно создать класс, который расширит абстрактный Service класс из библиотеки Finagle, реализуя его apply метод.

То, что мы делаем, похоже на реализацию функционального интерфейса . Интересно, однако, что на самом деле мы не можем использовать эту конкретную функцию, потому что Finagle написан на Scala, и мы используем преимущества взаимодействия Java и Scala:

public class GreetingService extends Service {
    @Override
    public Future apply(Request request) {
        String greeting = "Hello " + request.getParam("name");
        Reader reader = Reader.fromBuf(new Buf.ByteArray(greeting.getBytes(), 0, greeting.length()));
        return Future.value(Response.apply(request.version(), Status.Ok(), reader));
    }
}

4. Фильтр

Затем мы напишем фильтр, который будет записывать некоторые данные о запросе в консоль. Аналогично Service , нам нужно будет реализовать Filter ‘s apply метод, который будет принимать запрос и возвращать Будущий ответ, но на этот раз он также будет принимать службу в качестве второго параметра.

Базовый класс Filter имеет четыре параметра типа, но очень часто нам не нужно изменять типы запросов и ответов внутри фильтра.

Для этого мы будем использовать Простой фильтр , который объединяет четыре параметра типа в два. Мы напечатаем некоторую информацию из запроса, а затем просто вызовем метод apply из предоставленной службы:

public class LogFilter extends SimpleFilter {
    @Override
    public Future apply(Request request, Service service) {
        logger.info("Request host:" + request.host().getOrElse(() -> ""));
        logger.info("Request params:");
        request.getParams().forEach(entry -> logger.info("\t" + entry.getKey() + " : " + entry.getValue()));
        return service.apply(request);
    }
}

5. Сервер

Теперь мы можем использовать сервис и фильтр для создания сервера, который будет фактически прослушивать запросы и обрабатывать их.

Мы предоставим этому серверу службу, которая содержит как наш фильтр, так и службу, связанную вместе с методом andThen :

Service serverService = new LogFilter().andThen(new GreetingService()); 
Http.serve(":8080", serverService);

6. Клиент

Наконец, нам нужен клиент, чтобы отправить запрос на наш сервер.

Для этого мы создадим службу HTTP, используя удобный метод new Service из класса Http Finagle. Он будет нести прямую ответственность за отправку запроса.

Кроме того, мы будем использовать тот же фильтр ведения журнала, который мы реализовали ранее, и свяжем его со службой HTTP. Затем нам просто нужно будет вызвать метод apply .

Эта последняя операция является асинхронной, и ее конечные результаты хранятся в экземпляре Future . Мы могли бы дождаться этого Будущего , чтобы добиться успеха или потерпеть неудачу, но это была бы операция блокировки, и мы, возможно, захотим избежать ее. Вместо этого мы можем реализовать обратный вызов, который будет срабатывать при успешном выполнении Future :

Service clientService = new LogFilter().andThen(Http.newService(":8080"));
Request request = Request.apply(Method.Get(), "/?name=John");
request.host("localhost");
Future response = clientService.apply(request);

Await.result(response
        .onSuccess(r -> {
            assertEquals("Hello John", r.getContentString());
            return BoxedUnit.UNIT;
        })
        .onFailure(r -> {
            throw new RuntimeException(r);
        })
);

Обратите внимание, что мы возвращаем BoxedUnit.UNIT. Возврат Unit – это способ Scala справиться с методами void , поэтому мы делаем это здесь, чтобы поддерживать совместимость.

7. Резюме

В этом уроке мы узнали, как создать простой HTTP-сервер и клиент с помощью Finagle, а также как установить связь между ними и обмениваться сообщениями.

Как всегда, исходный код со всеми примерами можно найти на GitHub .