(Я чувствовал, что последние два режима менее документированы и нуждаются в некотором введении типа учебника, отсюда и мотивация этого сообщения). Чтобы легко следовать руководству, полезно иметь базовое представление об архитектуре Thrift, состоящей из транспортов, протоколов и процессоров. (Хорошую статью можно найти в [1]). Здесь я буду использовать версию 0 Thrift и привязку Java Thrift.
Комиссионная установка
Инструкции по установке можно найти по адресу http://wiki.apache.org/thrift/ThriftInstallation .
Подводя итог этапам установки Ubuntu.
1. Установите необходимые зависимости.
$ sudo apt-get install libboost-dev libboost-test-dev libboost-опции-программы-dev libevent-dev automake libtool flex bison pkg-config g ++ libssl-dev
2. Перейдите в корневой каталог установки.
3. $ ./configure
4. $ make
5. Станьте супер-пользователем и
$ make install
Теперь давайте приступим к созданию сервиса и его использованию.
Определение сервиса
Здесь определяется сервис с простыми арифметическими операциями. Обратите внимание на использование директивы typedef для объявления альтернативных имен для базовых типов i64 и i32. Добавьте следующее в файл с именем ‘ arithmetic.thrift ‘.
|
1
2
3
4
5
6
7
8
|
namespace java tutorial.arithmetic.gen // define namespace for java codetypedef i64 longtypedef i32 intservice ArithmeticService { // defines simple arithmetic servicelong add(1:int num1, 2:int num2),long multiply(1:int num1, 2:int num2),} |
Код будет сгенерирован в пакете tutorial.arithmetic.gen .
Теперь сгенерируйте Java-код, используя следующую командную строку.
$ thrift –gen java arithmetic.thrift
Будет создан исходный файл tutorial.arithmetic.gen.ArithmeticService.java .
Режим блокировки
Давайте создадим сервер режима блокировки и клиент для использования сервиса.
Сначала нам нужно реализовать сервис с использованием сгенерированного каркаса сервиса. Интерфейс для реализации — ArithmeticService.Iface.
|
01
02
03
04
05
06
07
08
09
10
11
|
public class ArithmeticServiceImpl implements ArithmeticService.Iface { public long add(int num1, int num2) throws TException { return num1 + num2; } public long multiply(int num1, int num2) throws TException { return num1 * num2; }} |
Теперь, когда это сделано, давайте создадим сервер Thrift, который будет запрашивать сервер для этого сервиса. Помните, что это блокирующий сервер, поэтому потоки сервера, выполняющие ввод / вывод, будут ждать.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class Server { private void start() { try { TServerSocket serverTransport = new TServerSocket(7911); ArithmeticService.Processor processor = new ArithmeticService.Processor(new ArithmeticServiceImpl()); TServer server = new TThreadPoolServer(new TThreadPoolServer.Args(serverTransport). processor(processor)); System.out.println("Starting server on port 7911 ..."); server.serve(); } catch (TTransportException e) { e.printStackTrace(); } } public static void main(String[] args) { Server srv = new Server(); srv.start(); }} |
Здесь используется реализация TThreadPoolServer, которая будет использовать пул потоков для обслуживания входящих запросов.
Теперь давайте напишем клиент.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
public class ArithmeticClient { private void invoke() { TTransport transport; try { transport = new TSocket("localhost", 7911); TProtocol protocol = new TBinaryProtocol(transport); ArithmeticService.Client client = new ArithmeticService.Client(protocol); transport.open(); long addResult = client.add(100, 200); System.out.println("Add result: " + addResult); long multiplyResult = client.multiply(20, 40); System.out.println("Multiply result: " + multiplyResult); transport.close(); } catch (TTransportException e) { e.printStackTrace(); } catch (TException e) { e.printStackTrace(); } } public static void main(String[] args) { ArithmeticClient c = new ArithmeticClient(); c.invoke(); }} |
TBinaryProtocol используется для кодирования данных, передаваемых между сервером и клиентом. Теперь запустите сервер и вызовите сервис, используя клиент для результатов.
Неблокирующий режим
Теперь давайте создадим неблокирующий сервер, который использует Java неблокирующий ввод / вывод. Мы можем использовать ту же реализацию сервиса, что и раньше (ArithmeticServiceImpl).
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
public class NonblockingServer { private void start() { try { TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(7911); ArithmeticService.Processor processor = new ArithmeticService.Processor(new ArithmeticServiceImpl()); TServer server = new TNonblockingServer(new TNonblockingServer.Args(serverTransport). processor(processor)); System.out.println("Starting server on port 7911 ..."); server.serve(); } catch (TTransportException e) { e.printStackTrace(); } } public static void main(String[] args) { NonblockingServer srv = new NonblockingServer(); srv.start(); }} |
Здесь используется TNonblockingServerSocket, который инкапсулирует ServerSocketChannel.
Код для неблокирующего клиента выглядит следующим образом.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public class NonblockingClient { private void invoke() { TTransport transport; try { transport = new TFramedTransport(new TSocket("localhost", 7911)); TProtocol protocol = new TBinaryProtocol(transport); ArithmeticService.Client client = new ArithmeticService.Client(protocol); transport.open(); long addResult = client.add(100, 200); System.out.println("Add result: " + addResult); long multiplyResult = client.multiply(20, 40); System.out.println("Multiply result: " + multiplyResult); transport.close(); } catch (TTransportException e) { e.printStackTrace(); } catch (TException e) { e.printStackTrace(); } } public static void main(String[] args) { NonblockingClient c = new NonblockingClient(); c.invoke(); }} |
Обратите внимание на использование TFramedTransport для переноса обычного транспорта TSocket. Неблокирующий сервер требует, чтобы клиент использовал TFramedTransport, который бы формировал данные, передаваемые по проводам. Запустите сервер и отправьте запрос с помощью клиента. Вы увидите те же результаты, что и раньше, на этот раз в режиме без блокировки.
Асинхронный режим
Мы можем написать асинхронные клиенты для вызова службы Thrift. Необходимо зарегистрировать обратный вызов, который будет вызван при успешном завершении запроса. Сервер в режиме блокировки не работает (вызов метода возвращается с пустым ответом) с асинхронным клиентом (возможно, это потому, что мы используем TNonblockingSocket на стороне клиента. См. Конструкцию ArithmeticService.AsyncClient . Так что это может быть правильным поведением). Сервер без блокировки режима, кажется, работает без проблем. Таким образом, вы можете использовать неблокирующий сервер с клиентом, показанным ниже.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
public class AsyncClient { private void invoke() { try { ArithmeticService.AsyncClient client = new ArithmeticService. AsyncClient(new TBinaryProtocol.Factory(), new TAsyncClientManager(), new TNonblockingSocket("localhost", 7911)); client.add(200, 400, new AddMethodCallback()); client = new ArithmeticService. AsyncClient(new TBinaryProtocol.Factory(), new TAsyncClientManager(), new TNonblockingSocket("localhost", 7911)); client.multiply(20, 50, new MultiplyMethodCallback()); } catch (TTransportException e) { e.printStackTrace(); } catch (TException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { AsyncClient c = new AsyncClient(); c.invoke(); } class AddMethodCallback implements AsyncMethodCallback<ArithmeticService.AsyncClient.add_call> { public void onComplete(ArithmeticService.AsyncClient.add_call add_call) { try { long result = add_call.getResult(); System.out.println("Add from server: " + result); } catch (TException e) { e.printStackTrace(); } } public void onError(Exception e) { System.out.println("Error : "); e.printStackTrace(); } } class MultiplyMethodCallback implements AsyncMethodCallback<ArithmeticService.AsyncClient.multiply_call> { public void onComplete(ArithmeticService.AsyncClient.multiply_call multiply_call) { try { long result = multiply_call.getResult(); System.out.println("Multiply from server: " + result); } catch (TException e) { e.printStackTrace(); } } public void onError(Exception e) { System.out.println("Error : "); e.printStackTrace(); } }} |
Два обратных вызова были определены в соответствии с каждой операцией службы. Обратите внимание на использование двух клиентских экземпляров для двух вызовов. Каждый вызов требует отдельного экземпляра клиента, иначе клиент потерпит неудачу со следующим исключением
« Исключение в потоке« main »java.lang.IllegalStateException: клиент в настоящее время выполняет другой метод: tutorial.arithmetic.gen.ArithmeticService $ AsyncClient $ add_call »
Так что это завершает мой быстрый старт на Thrift с различными режимами работы. Надеюсь, кто-нибудь может найти это полезным. Любые предложения или исправления не стесняйтесь комментировать.
[1] http://thrift.apache.org/static/thrift-20070401.pdf
Ссылка: Краткое руководство по Apache Thrift от нашего партнера JCG