Въведение във Finagle

1. Общ преглед

В този урок ще разгледаме набързо Finagle, RPC библиотеката на Twitter.

Ще го използваме за изграждане на прост клиент и сървър.

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

Преди да се задълбочим в изпълнението, трябва да се запознаем с основните концепции, които ще използваме, за да изградим нашето приложение. Те са широко известни, но могат да имат малко по-различно значение в света на Finagle.

2.1. Услуги

Услугите са функции, представени от класове, които приемат заявки и връщат бъдеще, съдържащо евентуалния резултат от операцията или информация за неуспеха.

2.2. Филтри

Филтрите също са функции. Те вземат заявка и услуга, извършват някои операции по заявката, предават я на услугата, правят някои операции върху полученото бъдеще и накрая връщат крайното бъдеще . Можем да ги възприемаме като аспекти, тъй като те могат да внедрят логика, която се случва около изпълнението на дадена функция и да променят нейния вход и изход.

2.3. Фючърси

Фючърсите представляват евентуалните резултати от асинхронните операции. Те може да са в едно от трите състояния: чакащи, успели или неуспешни.

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

Първо, ще приложим проста HTTP услуга за поздрави. Той ще вземе параметъра за име от заявката и ще отговори и ще добави обичайното съобщение „Здравей“.

За целта трябва да създадем клас, който ще разшири абстрактния клас Service от библиотеката на Finagle, прилагайки метода му за прилагане .

Това, което правим, изглежда подобно на внедряването на функционален интерфейс. Интересното е, че всъщност не можем да използваме тази специфична функция, защото 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. Филтър

След това ще напишем филтър, който ще регистрира някои данни за заявката в конзолата. Подобно на услугата , ще трябва да приложим метода за прилагане на филтъра , който ще вземе заявка и ще върне бъдещ отговор, но този път ще вземе услугата като втори параметър.

Основният клас на филтъра има четири типа параметри, но много често не е необходимо да променяме видовете заявки и отговори във филтъра.

За това ще използваме SimpleFilter, който обединява четирите параметъра тип в два. Ще отпечатаме малко информация от заявката и след това просто ще извикаме метода за прилагане от предоставената услуга:

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 услуга, използвайки удобния метод newService от Http класа на Finagle . Той ще бъде пряко отговорен за изпращането на заявката.

Освен това ще използваме същия филтър за регистриране, който сме внедрили преди, и ще го свържем с HTTP услугата. След това просто ще трябва да извикаме метода apply .

Последната операция е асинхронна и нейните евентуални резултати се съхраняват в бъдещия екземпляр. Можем да изчакаме това бъдеще да успее или да се провали, но това би било блокираща операция и може да искаме да го избегнем. Вместо това можем да приложим обратно извикване, което да се задейства, когато бъдещето успее:

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. Връщащата единица е начинът на Scala да се справи с методите на void , така че го правим тук, за да поддържаме оперативна съвместимост.

7. Обобщение

В този урок научихме как да изградим обикновен HTTP сървър и клиент с помощта на Finagle, както и как да установим комуникация между тях и да обменяме съобщения.

Както винаги, изходният код с всички примери може да бъде намерен в GitHub.