Смертельная серия из 9 вопросов от openFeign, кто выдержит это?

Java задняя часть

1. Введение

Паром душ в Spring Cloud был представлен ранее.Nacos, который не только мощный, но и очень простой в развертывании по сравнению со своими предшественниками.

Сегодня я представляю компонент сервисного вызова:OpenFeign, также является моделью, превосходящей своих предшественников (Ribbon,Feign) безжалостный характер.

Каталог статей выглядит следующим образом:

2. Что такое притворство?

Feign также является безжалостным персонажем, Feign стремится упростить Java HTTP-клиент.

Feign интегрирует Ribbon и RestTemplate для реализации Http-вызовов для балансировки нагрузки, но инкапсулирует исходный метод (Ribbon+RestTemplate). Разработчикам не нужно вручную использовать RestTemplate для настройки сервисов, но определить интерфейс, в этом интерфейсе можно использовать аннотацию для выполнить сервисный вызов, что больше соответствует целям интерфейсно-ориентированного программирования и упрощает разработку.

Но, к сожалению, сейчас Feign прекратил итерации, и, конечно же, многие компании сейчас его используют.

Читатели, которые хотят изучить Feign, могут перейти на официальный сайт весеннего облака, чтобы узнать. Чен не будет подробно представлять его здесь, не в центре внимания сегодня.

3. Что такое openFeign?

Я представил Feign, который останавливает итерацию.Проще говоря: OpenFeign — это аннотация, что springcloud поддерживает SpringMVC на основе Feign, например@RequestMappingи Т. Д. OpenFeign@FeignClientМожет анализировать SpringMVC@RequestMappingИнтерфейс под аннотацией и класс реализации генерируется динамическим прокси, балансировка нагрузки выполняется в классе реализации и вызываются другие сервисы.

Адрес официального сайта:docs.spring.IO/spring - уродливо...

4. В чем разница между Feign и openFeign?

Feign openFiegn
Feign — это облегченный клиент службы HTTP RESTful в компоненте SpringCloud.Feign имеет встроенную ленту, которая используется для балансировки нагрузки клиента для вызова служб реестра служб. Способ использования Feign: используйте аннотацию Feign для определения интерфейса, вызовите этот интерфейс, вы можете вызвать службу реестра служб. OpenFeign — это аннотация того, что SpringCloud поддерживает SpringMVC на основе Feign, например @RequestMapping. @FeignClient OpenFeign может анализировать интерфейс в соответствии с аннотацией SpringMVC @RequestMapping и генерировать классы реализации посредством динамического проксирования, балансировки нагрузки в классах реализации и вызова других сервисов.

5. Подготовка окружающей среды

Версия Spring Cloud, среда JDK и среда проекта в этой статье такие же, как и предыдущая среда Nacos:Пятьдесят пять картинок расскажут вам, насколько силен Nacos, перевозчик душ микросервисов?.

Реестр больше не будет использоватьсяEureka, используйте его напрямуюNacosВ качестве центра регистрации и настройки вы можете просмотреть статью Nacos, если не знаете, как это сделать.

Структура проекта, построенная в этой статье, выглядит следующим образом:

Использование центра регистрацииNacos, создать микросервис, который является поставщиком услугProduce, обслуживание потребителейConsumer.

6. Создайте поставщика услуг

Поскольку это взаимный вызов между микросервисами, должен быть поставщик услуг, создатьopenFeign-provider9005, зарегистрируйтесь в Nacos, конфигурация следующая:

server:
  port: 9005
spring:
  application:
    ## 指定服务名称,在nacos中的名字
    name: openFeign-provider
  cloud:
    nacos:
      discovery:
        # nacos的服务地址,nacos-server中IP地址:端口号
        server-addr: 127.0.0.1:8848
management:
  endpoints:
    web:
      exposure:
        ## yml文件中存在特殊字符,必须用单引号包含,否则启动报错
        include: '*'

Уведомление: здесьspring.application.nameУказанное имя будет использоваться в вызове интерфейса openFeign.

Исходный код проекта будет загружен, и будет доступен исходный код о том, как зарегистрироваться в Nacos и добавить любые зависимости.В сочетании с предыдущей статьей Чена о Nacos это не сложно!

7. Создайте потребителей услуг

создать новый модульopenFeign-consumer9006В качестве потребительского обслуживания шаги следующие.

1. Добавьте зависимости

В дополнение к зависимостям реестра Nacos также следует добавить зависимости openFeign, как показано ниже:

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

2. Добавьте аннотацию @EnableFeignClients, чтобы открыть функцию openFeign.

По-старому, добавьте аннотацию к основному классу запуска Spring boot.@EnableFeignClients, откройте функцию openFeign следующим образом:

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class OpenFeignConsumer9006Application
{
    public static void main(String[] args) {
        SpringApplication.run(OpenFeignConsumer9006Application.class, args);
    }
}

3. Создайте новый интерфейс openFeign

Создайте новый интерфейс openFeign и используйте@FeignClientАннотации отмечены следующим образом:

@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
}

Уведомление: аннотация@FeignClientсерединаvalueАтрибут указывает идентификатор поставщика услуг в реестре nacos.наименование услуги.

4. Создайте новый контроллер для отладки

Создайте новый контроллер для отладки интерфейса и прямого вызова интерфейса openFeign следующим образом:

@RestController
@RequestMapping("/openfeign")
public class OpenFeignController {
    
}

Хорошо, пока микросервис openFeign построен, никаких конкретных функций не реализовано, дальше немного реализации.

8. Как openFeign передает параметры?

Есть много способов передать параметры через интерфейс при разработке, но есть определенные правила передачи параметров в openFeign, которые подробно описаны ниже.

1. Передайте данные JSON

Это также часто используемое правило передачи параметров при разработке интерфейса, которое передается в Spring Boot.@RequestBodyОпределяет входные параметры.

Способ передачи параметров JSON в интерфейсе провайдера следующий:

@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {
    @PostMapping("/order2")
    public Order createOrder2(@RequestBody Order order){
        return order;
    }
}

Код передачи параметров в интерфейсе openFeign в потребителе выглядит следующим образом:

@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
    /**
     * 参数默认是@RequestBody标注的,这里的@RequestBody可以不填
     * 方法名称任意
     */
    @PostMapping("/openfeign/provider/order2")
    Order createOrder2(@RequestBody Order order);
}

Уведомление:openFeignСпособ передачи параметров по умолчанию — параметры передачи JSON (@RequestBody), поэтому нет необходимости определять интерфейс@RequestBodyАннотация выделена, но для уточнения обычно заполняется.

2, параметры формы POJO

Этот метод передачи параметров также более распространен, и параметры получают объекты POJO.

Код поставщика услуг PROVIDER выглядит следующим образом:

@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {
    @PostMapping("/order1")
    public Order createOrder1(Order order){
        return order;
    }
}

Потребительский потребительский код openFeign выглядит следующим образом:

@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
    /**
     * 参数默认是@RequestBody标注的,如果通过POJO表单传参的,使用@SpringQueryMap标注
     */
    @PostMapping("/openfeign/provider/order1")
    Order createOrder1(@SpringQueryMap Order order);
}

Многие люди в Интернете задаются вопросом, как передать параметры в форме POJO.Официальный документ четко дает решение, а именно:

openFeign предоставляет аннотацию@SpringQueryMapИдеальное решение для параметров формы POJO.

3. Параметры, передаваемые в URL

Этот метод также является распространенным методом запросов GET в методе restful.

Код провайдера услуг провайдера выглядит следующим образом:

@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {

    @GetMapping("/test/{id}")
    public String test(@PathVariable("id")Integer id){
        return "accept one msg id="+id;
}

Потребительский интерфейс openFeign выглядит следующим образом:

@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {

    @GetMapping("/openfeign/provider/test/{id}")
    String get(@PathVariable("id")Integer id);
}

использовать аннотации@PathVariableПолучайте заполнители в URL-адресе, этот способ хорошо понятен.

4. Обычные параметры формы

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

Код провайдера услуг провайдера выглядит следующим образом:

@RestController
@RequestMapping("/openfeign/provider")
public class OpenFeignProviderController {
    @PostMapping("/test2")
    public String test2(String id,String name){
        return MessageFormat.format("accept on msg id={0},name={1}",id,name);
    }
}

Параметры потребительского интерфейса OpenFeign следующие:

@FeignClient(value = "openFeign-provider")
public interface OpenFeignService {
    /**
     * 必须要@RequestParam注解标注,且value属性必须填上参数名
     * 方法参数名可以任意,但是@RequestParam注解中的value属性必须和provider中的参数名相同
     */
    @PostMapping("/openfeign/provider/test2")
    String test(@RequestParam("id") String arg1,@RequestParam("name") String arg2);
}

5. Резюме

Существует множество способов передачи параметров, таких как передача файлов... Здесь Чен Моу перечислил только четыре распространенных способа передачи параметров.

9. Как бороться с тайм-аутом?

Чтобы понять обработку таймаута, давайте рассмотрим пример: я засыпаю интерфейс службы провайдера на 3 секунды, интерфейс выглядит следующим образом:

@PostMapping("/test2")
public String test2(String id,String name) throws InterruptedException {
        Thread.sleep(3000);
        return MessageFormat.format("accept on msg id={0},name={1}",id,name);
}

На этом этапе мы вызываем интерфейс потребителя openFeign, чтобы вернуть результат, как показано ниже:

Очевидно, что программа работает ненормально, и возвращается таймаут вызова интерфейса. какие? Зачем? ............

openFeign на самом деле имеет тайм-аут по умолчанию, и по умолчанию это тайм-аут соединения.10秒, тайм-аут чтения60秒, исходный код находится вfeign.Request.Options#Options()В этом методе, как показано ниже:

Итак, возникает вопрос:Почему я устанавливаю сон только на 3 секунды и сообщаю о тайм-ауте?

На самом деле, openFeign интегрирует ленту.Тайм-аут соединения по умолчанию и тайм-аут чтения ленты составляет 1 секунду.Исходный код находится вorg.springframework.cloud.openfeign.ribbon.FeignLoadBalancer#execute()метод, как показано ниже:

Исходный код примерно: Если openFeign не устанавливает соответствующий тайм-аут, то будет использоваться тайм-аут ленты по умолчанию.

После понимания принципа настройки тайм-аута также очень ясно сгенерировать два решения, а именно:

  • Установить время ожидания openFeign
  • Установить время ожидания ленты

1. Установите время ожидания ленты (не рекомендуется)

Настройка очень проста, добавьте следующие настройки в файл конфигурации:

ribbon:
  # 值的是建立链接所用的时间,适用于网络状况正常的情况下, 两端链接所用的时间
  ReadTimeout: 5000
  # 指的是建立链接后从服务器读取可用资源所用的时间
  ConectTimeout: 5000

2. Установите время ожидания openFeign (рекомендуется)

Для openFeign очень просто установить период ожидания, его нужно только настроить в файле конфигурации следующим образом:

feign:
  client:
    config:
      ## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
      default:
        connectTimeout: 5000
        readTimeout: 5000

Настройкой по умолчанию является глобальный тайм-аут, который действителен для всех сервисов интерфейса openFeign.

Однако обычная бизнес-логика может включать несколько вызовов интерфейса openFeign, как показано на следующем рисунке:

Псевдокод на приведенном выше рисунке выглядит следующим образом:

public T invoke(){
    //1. 调用serviceA
    serviceA();
    
    //2. 调用serviceA
    serviceB();
    
    //3. 调用serviceA
    serviceC();
}

Так может ли глобальный тайм-аут, настроенный выше, пройти? очевидноserviceA,serviceBможно назвать успешно, ноserviceCОн не может быть успешно выполнен и должен сообщить об истечении времени ожидания.

В этот момент мы можем датьserviceCЭта служба настроена с отдельным периодом тайм-аута, конфигурация выглядит следующим образом:

feign:
  client:
    config:
      ## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
      default:
        connectTimeout: 5000
        readTimeout: 5000
      ## 为serviceC这个服务单独配置超时时间
      serviceC:
        connectTimeout: 30000
        readTimeout: 30000

Уведомление: период тайм-аута отдельной конфигурации переопределяет глобальную конфигурацию.

10. Как включить улучшение журнала?

Хотя openFeign предоставляет улучшения журналов, по умолчанию он не отображает никаких журналов, но разработчики могут сами настроить уровень журналов на этапе отладки.

Уровни журнала openFeign следующие:

  • NONE: по умолчанию логи не отображаются;
  • BASIC: записывайте только метод запроса, URL-адрес, код состояния ответа и время выполнения;
  • HEADERS: В дополнение к информации, определенной в BASIC, есть информация заголовка для запросов и ответов;
  • FULL: В дополнение к информации, определенной в HEADERS, тело и метаданные запроса и ответа.

Настройка также очень проста, шаги следующие:

1. Настройте уровень журнала в классе конфигурации

Вам необходимо настроить класс конфигурации, в котором будет установлен уровень журнала, следующим образом:

Уведомление: Регистратор здесь находится в пакете feign.

2. Установите уровень журнала интерфейса в файле yaml

Вам нужно только настроить уровень журнала указанного пакета или интерфейса openFeign в файле конфигурации следующим образом:

logging:
  level:
    cn.myjszl.service: debug

здесьcn.myjszl.serviceэто имя пакета, в котором находится интерфейс openFeign.Конечно, вы также можете настроить конкретный интерфейс openFeign.

3. Демонстрационный эффект

Вышеупомянутые шаги устанавливают журнал наFULL, в это время выполняется запрос, и эффект журнала выглядит следующим образом:

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

11. Как заменить стандартный httpclient?

Feign по умолчанию использует собственный JDK.URLConnectionПри отправке HTTP-запросов пул соединений отсутствует, но для каждого адреса поддерживается длительное соединение, то есть используется персистентное соединение HTTP.

В производственной среде HTTP-клиент по умолчанию обычно не используется, и обычно есть два варианта:

  • использоватьApacheHttpClient
  • использоватьOkHttp

Насчет того, что лучше, на самом деле у каждого свои достоинства.Я предпочитаю ApacheHttpClient.Все-таки это старый бренд, и со стабильностью проблем нет.

Так как его заменить? На самом деле это очень просто.В следующей демонстрации для замены используется ApacheHttpClient.

1. Добавьте зависимость ApacheHttpClient

Добавьте следующие зависимости в файл pom службы интерфейса openFeign:

<!--     使用Apache HttpClient替换Feign原生httpclient-->
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
    </dependency>
    
    <dependency>
      <groupId>io.github.openfeign</groupId>
      <artifactId>feign-httpclient</artifactId>
    </dependency>

Зачем добавлять вышеуказанные зависимости? Это не сложно увидеть из исходного кода, см.org.springframework.cloud.openfeign.FeignAutoConfiguration.HttpClientFeignConfigurationЭтот класс, код выглядит следующим образом:

Условия генерации в красной рамке выше, где@ConditionalOnClass(ApacheHttpClient.class), должен иметьApacheHttpClientЭтот класс вступит в силу, иfeign.httpclient.enabledЭта конфигурация должна быть установлена ​​наtrue.

2. Открыть в файле конфигурации

Для настройки open в конфигурационном файле код такой:

feign:
  client:
    httpclient:
      # 开启 Http Client
      enabled: true

3. Как убедиться, что замена прошла успешно?

На самом деле все очень просто, вfeign.SynchronousMethodHandler#executeAndDecode()Этот метод может четко видеть, какой клиент вызывается, как показано ниже:

Как видно на рисунке выше, последний вызовApacheHttpClient.

4. Резюме

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

12. Как оптимизировать общение?

Прежде чем мы поговорим о том, как оптимизировать, давайте посмотримGZIPАлгоритм сжатия, концепция заключается в следующем:

gzip — это формат данных, в котором для сжатия данных используется алгоритм deflate; gzip — это популярный алгоритм сжатия данных, который широко используется, особенно на платформе Linux.

Когда GZIP сжимает данные в виде простого текста, эффект очень очевиден, что может уменьшить размер данных более чем на 70%.

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

Принцип передачи со сжатием GZIP следующий:

Шаги для разборки в соответствии с приведенным выше рисунком следующие:

  • Заголовок запроса от клиента к серверу содержит:Accept-Encoding:gzip,deflateполе, указывающее серверу формат сжатия (gzip или deflate), поддерживаемый клиентом, если заголовок сообщения не отправлен, сервер не будет сжимать.
  • После того, как сервер получит запрос, если он обнаружит, что заголовок запроса содержитAccept-Encodingполе и поддерживает этот тип сжатия, сжать ответное сообщение и вернуть его клиенту, а также передатьContent-Encoding:gzipЗаголовок, указывающий, что ответное сообщение сжато в соответствии с этим форматом.
  • После того, как клиент получает ответ, он сначала определяет, есть ли заголовок Content-Encoding, и если да, распаковывает сообщение в этом формате. В противном случае оно обрабатывается как обычное сообщение.

поддержка openFeignответ на запросВключите сжатие GZIP, общий процесс выглядит следующим образом:

На приведенном выше рисунке есть только два блока, участвующих в передаче GZIP, а именноApplication client -> Application Service,Application Service->Application client.

Уведомление: GZIP, поддерживаемый openFeign, является только запросом и ответом интерфейса openFeign, то есть интерфейса для потребителей openFeign для вызова поставщиков услуг.

Шаги, чтобы открыть GZIP в openFeign, также очень просты, вам нужно только открыть следующую конфигурацию в файле конфигурации:

feign:
  ## 开启压缩
  compression:
    request:
      enabled: true
      ## 开启压缩的阈值,单位字节,默认2048,即是2k,这里为了演示效果设置成10字节
      min-request-size: 10
      mime-types: text/xml,application/xml,application/json
    response:
      enabled: true

После того, как описанная выше конфигурация завершена, отправьте запрос, вы можете ясно видеть, что заголовок запроса содержит сжатие GZIP, как показано ниже:

13. Как перейти на более раннюю версию?

Общие рамки понижения плавких предохранителей:Hystrix,Sentinel, то, что openFeign поддерживает по умолчанию, этоHystrix, это отражено в официальных документах, ведь он соотечественник, ха-ха......

Однако Sentinel от Ali полностью убивает Hystrix с точки зрения возможностей, простоты использования и других аспектов, поэтому в этой главе используетсяopenFeign+SentinelКонсолидация для снижения качества обслуживания.

инструкция: Я не фокусируюсь здесь на Sentinel, Чен намерен подробно рассказать о возможностях Sentinel в следующей статье.

1. Добавьте зависимости Sentinel

существуетopenFeign-consumer9006Файл pom потребителя добавляет дозорные зависимости (из-за использования модуля агрегации номер версии не указывается) следующим образом:

<dependency>
      <groupId>com.alibaba.cloud</groupId>
      <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

2. Включите понижение версии предохранителя Sentinel в файле конфигурации.

Если вы хотите, чтобы openFeign использовал функцию понижения версии sentinel, вам также необходимо открыть ее в файле конфигурации и добавить следующую конфигурацию:

feign:
  sentinel:
    enabled: true

3. Добавьте класс обратного вызова для перехода на более раннюю версию

Этот класс должен реализовывать тот же класс, что и интерфейс openFeign, как показано ниже:

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

4. Добавьте резервный атрибут

существует@FeignClientдобавлено вfallbackАтрибут, значением атрибута является класс обратного вызова понижения, как показано ниже:

@FeignClient(value = "openFeign-provider",fallback = OpenFeignFallbackService.class)
public interface OpenFeignService {}

5. Демонстрация

После вышеуказанных 4 шагов был установлен предохранитель и понижение версии openFeign, и эффект демонстрируется в это время.

Звонил почтальонhttp://localhost:9006/openfeign/order3Для этого интерфейса нормальная логика возвращается, как показано ниже:

Теперь вручную создайте исключение и сгенерируйте исключение в интерфейсе, предоставляемом службой, как показано ниже:

Напомним в этот моментhttp://localhost:9006/openfeign/order3, вернитесь к следующему рисунку:

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

Уведомление: В реальной разработке возвращаемые результаты должны быть единообразно настроены в соответствии с архитектурой Чен здесь просто для удобства демонстрации, не учитесь на этом, ха-ха. . .

14. Резюме

Эта статья в основном предназначена для новичков, а подробный исходный код и переход на более раннюю версию будут подробно представлены позже.Если текст неясен, пожалуйста, поправьте меня, если есть какая-то ошибка!

Это вторая статья Чена в расширенной колонке Spring Cloud. Я думаю, что статья хорошая. Добро пожаловать, лайкните, добавьте в избранное и вперед.

Приведенный выше исходный код был загружен на GitHub, требуемый общедоступный номер [Code Ape Technology Column] отвечает ключевым словам.9528Получать.