Ant Financial SOFA-Boot интегрирует SOFA-RPC (часть 2)

Java задняя часть Архитектура Dubbo

предисловие

В прошлой статье кратко были представлены возможности 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

Конфигурация фильтра вступает в силу, и итоговая последовательность перехвата фильтра выглядит следующим образом:

  1. Клиент инициирует вызов -> перехват интерфейса клиента -> перехват интерфейса на стороне сервера
  2. выполнение серверного метода
  3. Перехват сообщения сервера -> Перехват сообщения клиента -> Клиент получает возвращаемое значение

резюме

В этом документе представлен централизованный метод вызова SOFA-RPC, в том числе односторонний вызов, синхронный вызов, вызов в будущем и обратный вызов, представлен уникальный обобщающий механизм вызова SOFA-RPC, а также кратко представлена ​​конфигурация фильтров.


Добро пожаловать в технический публичный аккаунт: Zero One Technology Stack

零壹技术栈

Эта учетная запись будет продолжать делиться сухими товарами серверных технологий, включая основы виртуальных машин, многопоточное программирование, высокопроизводительные фреймворки, асинхронное ПО, промежуточное ПО для кэширования и обмена сообщениями, распределенные и микросервисы, материалы для обучения архитектуре и расширенные учебные материалы и статьи.