предисловие
В прошлой статье кратко были представлены возможности SOFA-Boot, а также приведен пример настройки проверки работоспособности Readiness. Он фокусируется на том, как внедрить промежуточное ПО SOFA-RPC в SOFA-Boot, и описывает весь процесс публикации и использования службы на основе различных каналов протокола, таких как Bolt, Rest и Dubbo.
В этой статье будут дополнительно представлены богатые и мощные функции, предоставляемые промежуточным программным обеспечением SOFA-RPC, включая односторонние вызовы, синхронные вызовы, будущие вызовы, обратные вызовы, обобщенные вызовы, настройку фильтров и т. д.
Другие статьи
текст
1. Как звонить
SOFA-RPC предоставляет четыре механизма вызова: односторонний вызов, синхронный вызов, асинхронный вызов и обратный вызов. Чтобы различить разницу между четырьмя, вот схематическая диаграмма, официально предоставленная SOFA.
Подробное описание и инструкции по настройке приведены ниже:
1.1. Односторонний режим
После того, как текущий поток инициирует вызов, он не заботится о результате вызова и не контролирует время ожидания, пока запрос отправлен, вызов завершен. Протокол Bolt в настоящее время поддерживается.
Инструкции по настройке
Использование одностороннего метода требуетслужебная ссылкапри прохождении черезsofa:global-attrs
элементальtype
Метод вызова объявления свойстваoneway
, чтобы при использовании ссылки на службу для инициирования вызова использовался односторонний метод.
<sofa:reference id="helloOneWayServiceReference" interface="com.ostenant.sofa.rpc.example.invoke.HelloOneWayService">
<sofa:binding.bolt>
<sofa:global-attrs type="oneway"/>
</sofa:binding.bolt>
</sofa:reference>
Применимая сцена
Успех одностороннего вызова не гарантируется, и инициатор не может знать результат вызова. Поэтому он обычно используется в сценариях, которые можно повторять или периодически уведомлять.Вызывающий процесс может завершиться ошибкой из-за сетевых проблем, сбоев машины и других причин. Бизнес-сценарии должны быть в состоянии принять такие аномальные сценарии, прежде чем их можно будет использовать.
1.2 Синхронизация
После того как текущий поток инициирует вызов, ему необходимо дождаться результата ответа в течение заданного периода времени ожидания, чтобы завершить вызов. Если в течение периода тайм-аута результат не получен, будет выдано исключение тайм-аута.
Инструкции по настройке
Интерфейс службы и класс реализации
SOFA-RPC по умолчанию использует синхронные вызовы, которые можно опустить.sofa:global-attrs
элемент конфигурации.
Конфигурация выпуска сервера
<bean id="helloSyncServiceImpl" class="com.ostenant.sofa.rpc.example.invoke.HelloSyncServiceImpl"/>
<sofa:service ref="helloSyncServiceImpl" interface="com.ostenant.sofa.rpc.example.invoke.HelloSyncService">
<sofa:binding.bolt/>
</sofa:service>
Эталонная конфигурация клиента
<sofa:reference id="helloSyncServiceReference" interface="com.ostenant.sofa.rpc.example.invoke.HelloSyncService">
<sofa:binding.bolt/>
</sofa:reference>
Запись запуска сервера
SpringApplication springApplication = new SpringApplication(SyncServerApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Запись запуска клиента
SpringApplication springApplication = new SpringApplication(SyncClientApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Звонок клиента
HelloSyncService helloSyncServiceReference = (HelloSyncService) applicationContext.getBean("helloSyncServiceReference");
System.out.println(helloSyncServiceReference.saySync("sync"));
Применимая сцена
Синхронные вызовы являются наиболее распространенным способом. Обратите внимание, что период тайм-аута должен быть установлен разумно в соответствии с возможностями обработки однорангового узла.
1.3 Метод будущего
В режиме Future клиент не ждет результата от сервера после инициации вызова, а продолжает выполнять последующую бизнес-логику. Результат, возвращаемый сервером, будет кэшироваться SOFA-RPC.Когда клиенту нужен результат, он должен взять на себя инициативу для его получения. Протокол Bolt в настоящее время поддерживается.
Инструкции по настройке
Интерфейс службы и класс реализации
HelloFutureService.java
public interface HelloFutureService {
String sayFuture(String future);
}
HelloFutureServiceImpl.java
public class HelloFutureServiceImpl implements HelloFutureService {
@Override
public String sayFuture(String future) {
return future;
}
}
Конфигурация выпуска сервера
<bean id="helloFutureServiceImpl" class="com.ostenant.sofa.rpc.example.invoke.HelloFutureServiceImpl"/>
<sofa:service ref="helloFutureServiceImpl" interface="com.ostenant.sofa.rpc.example.invoke.HelloFutureService">
<sofa:binding.bolt/>
</sofa:service>
Эталонная конфигурация клиента
Чтобы использовать метод Future, вам нужно передать ссылку на сервисsofa:global-attrs
элементальtype
Метод вызова объявления свойстваfuture
.
<sofa:reference id="helloFutureServiceReference" interface="com.ostenant.sofa.rpc.example.invoke.HelloFutureService">
<sofa:binding.bolt>
<sofa:global-attrs type="future"/>
</sofa:binding.bolt>
</sofa:reference>
Это то, что используется, когда вызов выполняется с использованием ссылки на услугуFuture
тоже.
Запись запуска сервера
SpringApplication springApplication = new SpringApplication(FutureServerApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Запись запуска клиента
SpringApplication springApplication = new SpringApplication(FutureClientApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Клиент может получить возвращаемый результат двумя способами:
- Во-первых, через
SofaResponseFuture
Получите результат напрямую. Первый параметр — это тайм-аут для получения результата, а второй параметр указывает, следует ли очищать результат в контексте потока.
HelloFutureService helloFutureServiceReference = (HelloFutureService) applicationContext
.getBean("helloFutureServiceReference");
helloFutureServiceReference.sayFuture("future");
try {
String result = (String)SofaResponseFuture.getResponse(1000, true);
System.out.println("Future result: " + result)
} catch (InterruptedException e) {
e.printStackTrace();
}
- Во-вторых, получить родной Future. Этот метод получит собственный Future JDK, а параметр указывает, следует ли очищать результат в контексте потока. Путь к результату — это путь к JDK Future.
HelloFutureService helloFutureServiceReference = (HelloFutureService) applicationContext
.getBean("helloFutureServiceReference");
helloFutureServiceReference.sayFuture("future");
try {
Future future = SofaResponseFuture.getFuture(true);
String result = (String)future.get(1000, TimeUnit.MILLISECONDS);
System.out.println("Future result: " + result)
} catch (InterruptedException e) {
e.printStackTrace();
}
Применимая сцена
Метод Future подходит для неблокирующего режима программирования. После обработки клиентской программы нет необходимости сразу получать возвращаемый результат, последующее выполнение программного кода может быть завершено первым, а в последующем бизнесе результат возврата вызова активно получается из контекста текущего потока. Уменьшена блокировка выполнения кода и задержки, вызванные ожиданием сетевого ввода-вывода.
1.4. Метод обратного вызова
Если текущий поток инициирует вызов, вызов немедленно завершается, и следующий вызов может быть выполнен немедленно. Обратный вызов необходимо зарегистрировать при инициировании вызова, а обратный вызов должен выделить пул асинхронных потоков. После возврата ответа логика обратного вызова будет выполняться в пуле асинхронных потоков обратного вызова.
Инструкции по настройке
Интерфейс службы и класс реализации
HelloCallbackService.java
public interface HelloCallbackService {
String sayCallback(String callback);
}
HelloCallbackServiceImpl.java
public class HelloCallbackServiceImpl implements HelloCallbackService {
@Override
public String sayCallback(String string) {
return string;
}
}
бизнес-класс обратного вызова
Клиентский класс обратного вызова должен быть реализованcom.alipay.sofa.rpc.core.invoke.SofaResponseCallback
интерфейс.
CallbackImpl.java
public class CallbackImpl implements SofaResponseCallback {
@Override
public void onAppResponse(Object appResponse, String methodName, RequestBase request) {
System.out.println("callback client process:" + appResponse);
}
@Override
public void onAppException(Throwable throwable, String methodName, RequestBase request) {
}
@Override
public void onSofaException(SofaRpcException sofaException, String methodName, RequestBase request) {
}
}
Интерфейс SofaResponseCallback предоставляет 3 метода:
- onAppResponse: если программа работает нормально, введите этот метод обратного вызова.
- onAppException: если серверная программа выдает исключение, введите метод обратного вызова.
- onSofaException: если внутри фреймворка возникла ошибка, введите этот метод обратного вызова.
Конфигурация выпуска сервера
<bean id="helloCallbackServiceImpl" class="helloFutureServiceReference" interface="com.ostenant.sofa.rpc.example.invoke.HelloCallbackServiceImpl"/>
<sofa:service ref="helloCallbackServiceImpl" interface="helloFutureServiceReference" interface="com.ostenant.sofa.rpc.example.invoke.HelloCallbackService">
<sofa:binding.bolt/>
</sofa:service>
Эталонная конфигурация клиента
Проходит при ссылке на службуsofa:global-attrs
элементальtype
Метод вызова объявления свойстваcallback
, затем пройтиcallback-ref
Объявите класс реализации обратного вызова.
<bean id="callbackImpl" class="com.ostenant.sofa.rpc.example.invoke.CallbackImpl"/>
<sofa:reference id="helloCallbackServiceReference"
interface="com.ostenant.sofa.rpc.example.invoke.HelloCallbackService">
<sofa:binding.bolt>
<sofa:global-attrs type="callback" callback-ref="callbackImpl"/>
</sofa:binding.bolt>
</sofa:reference>
Таким образом, когда ссылка на службу используется для инициирования вызова, используется метод обратного вызова. Когда результат возвращается, SOFA-RPC автоматически вызывает соответствующий метод класса обратного вызова.
Запись запуска сервера
SpringApplication springApplication = new SpringApplication(CallbackServerApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Запись запуска клиента
SpringApplication springApplication = new SpringApplication(CallbackClientApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Клиент инициирует вызов
HelloCallbackService helloCallbackServiceReference = (HelloCallbackService) applicationContext
.getBean("helloCallbackServiceReference");
helloCallbackServiceReference.sayCallback("callback");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Возвращаемое значение sayCallback() не должно быть получено напрямую. В классе обратного вызова, зарегистрированном клиентом, возвращаемое значение будет передано в правильный метод в виде параметра, а последующая логическая обработка будет завершена в виде обратного вызова.
Применимая сцена
Метод Callback подходит для асинхронного неблокирующего режима программирования. После того как поток, в котором находится клиентская программа, инициирует вызов, он продолжает выполнять последующие операции без активного получения возвращаемого значения. После завершения обработки программы на стороне сервера возвращаемое значение возвращается в пул асинхронных потоков, а дочерний поток обрабатывает возвращаемое значение с помощью функции обратного вызова. Это значительно уменьшает блокировку сетевого ввода-вывода, устраняет узкое место, связанное с одним потоком, и реализует асинхронное программирование.
2. Обобщенный вызов
Обобщенный метод вызова может инициировать вызовы, не полагаясь на интерфейс сервера, и в настоящее время поддерживает протокол Bolt. Поскольку интерфейс сервера неизвестен, то интерфейс сервера, вызываемый метод, параметры и класс результата необходимо описать в виде строк.
Инструкции по настройке
Обобщенный класс параметров
SampleGenericParamModel.java
public class SampleGenericParamModel {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
обобщенный класс возврата
SampleGenericResultModel.java
public class SampleGenericResultModel {
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Интерфейс службы и класс реализации
SampleGenericService.java
public interface SampleGenericService {
SampleGenericResultModel sayGeneric(SampleGenericParamModel sampleGenericParamModel);
}
-
SampleGenericParamModel: В качестве типа входного параметра sayGeneric() используется
name
Переменные-члены как реальные параметры метода. -
SampleGenericResultModel: поскольку возвращаемый тип результата sayGeneric() объявляет
name
а такжеvalue
Две переменные-члены в качестве реального возвращаемого значения.
SampleGenericServiceImpl.java
public class SampleGenericServiceImpl implements SampleGenericService {
@Override
public SampleGenericResultModel sayGeneric(SampleGenericParamModel sampleGenericParamModel) {
String name = sampleGenericParamModel.getName();
SampleGenericResultModel resultModel = new SampleGenericResultModel();
resultModel.setName(name);
resultModel.setValue("sample generic value");
return resultModel;
}
}
Конфигурация выпуска сервера
<bean id="sampleGenericServiceImpl" class="com.ostenant.sofa.rpc.example.generic.SampleGenericServiceImpl"/>
<sofa:service ref="sampleGenericServiceImpl" interface="com.ostenant.sofa.rpc.example.generic.SampleGenericService">
<sofa:binding.bolt/>
</sofa:service>
Эталонная конфигурация клиента
<sofa:reference id="sampleGenericServiceReference" interface="com.alipay.sofa.rpc.api.GenericService">
<sofa:binding.bolt>
<sofa:global-attrs generic-interface="com.ostenant.sofa.rpc.example.generic.SampleGenericService"/>
</sofa:binding.bolt>
</sofa:reference>
В процессе вызова обобщения необходимо отметить два момента в конфигурации клиента:
-
sofa:reference
Интерфейс указанной службы должен быть объявлен как обобщенный интерфейс, предоставляемый SOFA-RPC.com.alipay.sofa.rpc.api.GenericService
. -
sofa:global-attrs
Необходимо объявить свойстваgeneric-interface
, value — это реальное имя интерфейса службы.
Запись запуска сервера
SpringApplication springApplication = new SpringApplication(SampleGenericServerApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Запись запуска клиента
SpringApplication springApplication = new SpringApplication(SampleGenericClientApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Клиент инициирует вызов
- Получить обобщенную справку по услуге
GenericService sampleGenericServiceReference = (GenericService) applicationContext
.getBean("sampleGenericServiceReference");
- Подготовить параметры метода
Поскольку у клиента нет класса параметров для вызова службы, передайтеcom.alipay.hessian.generic.model.GenericObjectGenericObject
описывать.
// 准备方法参数
GenericObject genericParam = new GenericObject(
"com.ostenant.sofa.rpc.example.generic.SampleGenericParamModel");
genericParam.putField("name", "Harrison");
GenericObject
держи одинMap<String, Object>
переменная типа, вы можете передатьGenericObject
который предоставилputField()
метод, поместите свойства и значения класса параметра в этотMap
, чтобы описать класс параметров.
- сделать обобщающий звонок
пройти черезGenericService
из$genericInvoke(arg1, agr2, arg3)
Метод может инициировать обобщенный вызов сервиса, значение каждого параметра следующее:
параметр | имея в виду | необязательный параметр |
---|---|---|
arg1 | имя целевого метода | необходимые |
arg2 | Массив типов параметров, требующих строгого порядка старшинства | необходимые |
arg3 | Массив значений параметров, который должен соответствовать массиву типов параметров. | необходимые |
arg4 | Тип класса возвращаемого значения | необязательный |
метод первый:
GenericObject genericResult = (GenericObject) sampleGenericServiceReference.$genericInvoke(
// 目标方法名称
"sayGeneric",
// 参数类型名称
new String[] { "com.ostenant.sofa.rpc.example.generic.SampleGenericParamModel" },
// 参数的值
new Object[] { genericParam });
// 验证返回结果
System.out.println("Type: " + genericResult.getType());
System.out.println("Name: " + genericResult.getField("name"));
System.out.println("Value: " + genericResult.getField("value"));
Способ второй:
SampleGenericResultModel sampleGenericResult = sampleGenericServiceReference.$genericInvoke(
// 目标方法名称
"sayGeneric",
// 参数类型名称
new String[] { "com.ostenant.sofa.rpc.example.generic.SampleGenericParamModel" },
// 参数的值
new Object[] { genericParam },
// 返回值的Class类型
SampleGenericResultModel.class);
// 验证返回结果
System.out.println("Type: " + sampleGenericResult.getClass().getName());
System.out.println("Name: " + sampleGenericResult.getName());
System.out.println("Value: " + sampleGenericResult.getValue());
Просмотр вывода консоли
Результат двух методов следующий:
Type: com.ostenant.sofa.rpc.example.generic.SampleGenericResultModel
Name: Harrison
Value: sample generic value
3. Конфигурация фильтра
SOFA-RPC реализует перехват запросов и ответов через фильтры. Пользователи могут настроить фильтр для реализации расширений перехвата, и в настоящее время он поддерживает протокол Bolt. разработчики по наследствуcom.alipay.sofa.rpc.filter.Filter
Внедрение пользовательских фильтров.
Инструкции по настройке
Интерфейс службы и класс реализации
FilterService.java
public interface FilterService {
String sayFilter(String filter);
}
FilterServiceImpl.java
public class FilterServiceImpl implements FilterService {
@Override
public String sayFilter(String filter) {
return filters;
}
}
фильтр сервера
В классе реализации фильтраinvoke()
Метод реализует определенную логику перехвата, посредствомFilterInvoker.invoke(SofaRequest)
Инициируйте вызов службы, и конкретная обработка перехвата может быть реализована до и после метода.
public class SampleServerFilter extends Filter {
@Override
public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException {
System.out.println("SampleFilter before server process");
try {
return invoker.invoke(request);
} finally {
System.out.println("SampleFilter after server process");
}
}
}
Конфигурация выпуска сервера
Серверу необходимо настроить класс реализации службы, фильтр, а затемsofa:service
изsofa:global-attrs
Конфигурация этикеткиfilter
свойства для реализации привязки двух.
<bean id="sampleFilter" class="com.ostenant.sofa.rpc.example.filter.SampleServerFilter"/>
<bean id="filterService" class="com.ostenant.sofa.rpc.example.filter.FilterServiceImpl"/>
<sofa:service ref="filterService" interface="com.ostenant.sofa.rpc.example.filter.FilterService">
<sofa:binding.bolt>
<sofa:global-attrs filter="sampleFilter"/>
</sofa:binding.bolt>
</sofa:service>
клиентский фильтр
public class SampleClientFilter extends Filter {
@Override
public SofaResponse invoke(FilterInvoker invoker, SofaRequest request) throws SofaRpcException {
System.out.println("SampleFilter before client invoke");
try {
return invoker.invoke(request);
} finally {
System.out.println("SampleFilter after client invoke");
}
}
}
Эталонная конфигурация клиента
Аналогично, фильтры на стороне клиента должны бытьsofa:reference
изsofa:global-attrs
конфигурация на этикеткеfilter
Атрибут для реализации перехвата вызовов клиентского эталонного класса.
<bean id="sampleFilter" class="com.alipay.sofa.rpc.samples.filter.SampleClientFilter"/>
<sofa:reference id="filterServiceReference" interface="com.ostenant.sofa.rpc.example.filter.FilterService">
<sofa:binding.bolt>
<sofa:global-attrs filter="sampleFilter"/>
</sofa:binding.bolt>
</sofa:reference>
Класс запуска сервера
SpringApplication springApplication = new SpringApplication(FilterServerApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Класс запуска клиента
SpringApplication springApplication = new SpringApplication(FilterClientApplication.class);
ApplicationContext applicationContext = springApplication.run(args);
Звонок клиента
FilterService filterServiceReference = (FilterService) applicationContext.getBean("filterServiceReference");
try {
// sleep 5s, 便于观察过滤器效果
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String result = filterServiceReference.sayFilter("filter");
System.out.println("Invoke result: " + result);
Просмотр результатов перехвата
- распечатка сервера
SampleFilter before server process
SampleFilter after server process
- Распечатка клиента
SampleFilter before client invoke
SampleFilter after client invoke
Invoke result: filter
Конфигурация фильтра вступает в силу, и итоговая последовательность перехвата фильтра выглядит следующим образом:
- Клиент инициирует вызов -> перехват интерфейса клиента -> перехват интерфейса на стороне сервера
- выполнение серверного метода
- Перехват сообщения сервера -> Перехват сообщения клиента -> Клиент получает возвращаемое значение
резюме
В этом документе представлен централизованный метод вызова SOFA-RPC, в том числе односторонний вызов, синхронный вызов, вызов в будущем и обратный вызов, представлен уникальный обобщающий механизм вызова SOFA-RPC, а также кратко представлена конфигурация фильтров.
Добро пожаловать в технический публичный аккаунт: Zero One Technology Stack
Эта учетная запись будет продолжать делиться сухими товарами серверных технологий, включая основы виртуальных машин, многопоточное программирование, высокопроизводительные фреймворки, асинхронное ПО, промежуточное ПО для кэширования и обмена сообщениями, распределенные и микросервисы, материалы для обучения архитектуре и расширенные учебные материалы и статьи.