SpringCloud Series (5) | Интегрируйте OpenFeign для реализации межсервисных вызовов
SpringCloud Series (5) | Интегрируйте OpenFeign для реализации межсервисных вызовов

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

1. Функция регистрационного центра

Центр регистрации служб является основным компонентом управления на основе служб. Он аналогичен роли служб каталогов. Он в основном используется для хранения информации о службах, например, о поставщиках. url нить、Информация о маршруте и т. д.。Служить Регистрационный центр находитсямикросервисыАрхитектура Один из самых основных объектов в。

Центр регистрации можно назвать «адресной книгой» в микросервисах Архитектура.,он записывает Служитьи Служить Отношения сопоставления адресов。существоватьраспределенныйАрхитектурасередина,Служить зарегистрируется здесь,Когда Служить нужно позвонить другому Служить,Просто зайдите сюда, чтобы найти адрес Служить.,Позвоните.

Простое понимание таково: когда нет центра регистрации, для вызовов между службами должен быть известен конкретный адрес вызывающей службы (жестко заданный ip:port). Чтобы изменить адрес развертывания, вам необходимо изменить адрес, указанный в вызове. В центре регистрации каждой службе необходимо знать только имя службы (мягкое кодирование) при звонке другим, и адрес будет вызываться через центр регистрации для получения конкретного адреса службы на основе имени службы.

Основные функции регистрационного центра

  • Служить Реестр: Основные функции регистрационного центра,Запишите информацию о каждом поставщике Служить,Например, Служить имя, IP, порт и т.д. Поддерживать Служить информацию об абонентах.
  • Служить регистрацию и отмену интерфейса: Обеспечить Служить регистрацию и отмену интерфейса для Служить провайдерам.
  • Проверка здоровья и удаление Служить: предоставить интерфейс отчетности о состоянии здоровья зарегистрированным Служить, чтобы загрузить информацию о состоянии здоровья для выживания Служить. При этом вышедшие из строя узлы можно вовремя удалить и синхронизировать со Служить абонентам.
  • Подписка «Служить» и уведомление об изменении: для потребителей «Служить»

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

2. Введение в OpenFeign

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

Что именно умеет OpenFeign:

  • OpenFeign создан для упрощения Java. Разработка Httpклиента. Feign выполнил дальнейшую инкапсуляцию на основе restTemplate, которая помогает нам определить и реализовать определение зависимости Служить интерфейс. С помощью OpenFeign нам нужно только создать интерфейс и настроить его с помощью аннотаций (аналогично аннотациям Mapper выше Daointerface), чтобы завершить привязку интерфейса к провайдеру Служить, что значительно упрощает Spring. cloud Развитие Ribbon автоматически отражает объем развития Служить звонящим клиентам.
  • OpenFeign интегрирует ленту,использоватьribbonподдерживается Служитьсписок,А балансировка нагрузки клиента реализована через ленту. Отличие от ленты в том, что,Через OpenFeign вам нужно только определить Служить привязку интерфейса и использовать декларативный метод.,Элегантная и простая реализация вызова Служить.

Еще следует отметить, что на самом деле существует разница между openFeign и feign. Проще говоря, feign обычно используется старой версией Springcloud. Позже она больше не поддерживается, поэтому был выпущен openfeign, и некоторые варианты использования были оптимизированы. . Вы также можете проверить подробные различия в Интернете.

3. Разработка интерфейса

Сначала мы добавляем несколько интерфейсов в сервисы userservice и orderservice. Удобно наблюдать за результатами звонка.

Давайте сначала интегрируем несколько классов унифицированной инкапсуляции результатов, упомянутых ранее, в общий модуль. Если вам это не совсем понятно, вы можете найти мою предыдущую статью: «Унифицированная инкапсуляция результатов SpringBoot». Основные категории следующие:

Затем мы создаем UserController в userservice. Сначала просто разработайте интерфейс.

Язык кода:javascript
копировать
package com.lsqingfeng.springcloud.user.controller;

import com.lsqingfeng.springcloud.common.base.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @className: UserController
 * @description:
 * @author: sh.Liu
 * @date: 2022-03-29 17:25
 */
@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("hello")
    public Result hello(String name){
        return Result.success(name);
    }

}

Аналогичным образом мы также создаем Контроллер в модуле orderservice и разрабатываем интерфейс.

Язык кода:javascript
копировать
package com.lsqingfeng.springcloud.order.controller;

import com.lsqingfeng.springcloud.common.base.Result;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @className: OrderController
 * @description:
 * @author: sh.Liu
 * @date: 2022-03-29 17:54
 */
@RestController
@RequestMapping("/order")
public class OrderController {

    @GetMapping("getOrder")
    public Result getOrder(String orderNo){
        return Result.success(orderNo);
    }

}

Запустите две программы и давайте протестируем эти два интерфейса.

пользовательский интерфейс:

интерфейс заказа:

4. Интегрируйте OpenFeign

Прежде всего, позвольте мне объяснить, что OpenFeign не принадлежит системе SpringCloud Alibaba. Это независимая техническая архитектура. Из каталога SpringCloud мы также видим, что на самом деле она находится на том же уровне, что и SpringCloud Alibaba. Но это не влияет на его использование в архитектуре SpringCloud Alibaba, и он полностью совместим в использовании.

Функция самого OpenFein на самом деле заключается в вызове между сервисами. Конечно, такой вызов можно осуществлять и другими способами. Например, dubbo в системе SpringCloud Alibaba сам осуществляет RPC-вызовы и существовал до появления SpringCloud. был активен в течение длительного времени, поэтому в области вызова сервисов мы можем использовать OpenFeign или dubbo, но, по моим наблюдениям, OpenFeign все еще используется чаще. Dubbo часто используется вместе с Zookeeper для выполнения распределенных вызовов RPC. Если позже у нас будет время, мы также интегрируем dubbo для реализации вызовов между сервисами.

Хорошо, теперь, когда общее введение завершено, давайте реализуем небольшое требование: orderservice вызывает интерфейс userservice через OpenFeign.

4.1 Введение зависимостей

Потому что все наши зависимости управляются единообразно в родительском модуле. Теперь нам нужно использовать связанные зависимости SpringCloud, поэтому добавьте их:

Язык кода:javascript
копировать
<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-dependencies</artifactId>
      <version>${spring.cloud-version}</version>
      <type>pom</type>
      <scope>import</scope>
</dependency>

Информация о версии: <spring.cloud-version>2021.0.1</spring.cloud-version>

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

Язык кода:javascript
копировать
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.lsqingfeng.springcloud</groupId>
        <artifactId>spring-cloud-learning</artifactId>
        <version>1.0.0</version>
    </parent>

    <artifactId>spring-cloud-learning-parent</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    <name>spring-cloud-learning-parent</name>
    <description>Родитель проектаpom,раньше передавался по наследству</description>

    <properties>
        <java.version>17</java.version>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>

        <spring.boot.version>2.6.5</spring.boot.version>
        <spring.cloud.alibaba.version> 2021.0.1.0</spring.cloud.alibaba.version>
        <spring.cloud-version>2021.0.1</spring.cloud-version>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <lombok.version>1.18.20</lombok.version>
        <nacos.version>0.2.1</nacos.version>
        <modelmapper.version>2.3.0</modelmapper.version>
        <springfox-swagger2.version>2.9.2</springfox-swagger2.version>
        <xiaoymin.swagger.version>1.9.6</xiaoymin.swagger.version>

    </properties>

    <repositories>
        <!-- mavenНа складе используется Alibaba Cloud.-->
        <repository>
            <id>maven-ali</id>
            <url>http://maven.aliyun.com/nexus/content/groups/public//</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
                <updatePolicy>always</updatePolicy>
                <checksumPolicy>fail</checksumPolicy>
            </snapshots>
        </repository>
    </repositories>


    <dependencyManagement>
        <dependencies>
            <!-- springBoot Зависимость версии -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>

            <!-- springCloud-alibabaЗависимость версии-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- Зависимости, связанные с SpringCloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>com.lsqingfeng.springcloud</groupId>
                <artifactId>spring-cloud-learning-common</artifactId>
                <version>${project.parent.version}</version>
            </dependency>

            <!-- lombok -->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
            </dependency>

            <!-- Инструмент копирования объектов -->
            <dependency>
                <groupId>org.modelmapper</groupId>
                <artifactId>modelmapper</artifactId>
                <version>${modelmapper.version}</version>
            </dependency>

            <!-- swagger -->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>${springfox-swagger2.version}</version>
            </dependency>
            <dependency>
                <groupId>com.github.xiaoymin</groupId>
                <artifactId>swagger-bootstrap-ui</artifactId>
                <version>${xiaoymin.swagger.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Затем настройте зависимости на нашей потребительской стороне. Наш потребитель — это вызывающий абонент службы orderservice.

Язык кода:javascript
копировать
<!--openfeign -->
<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

4.2 Разработка клиентского интерфейса OpenFeign

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

Затем мы создаем пакет специально для размещения симулируемого клиентского интерфейса. Просто назовите его клиентом. Затем создайте внутри него интерфейс. Пользователь Фигн Клиент. Содержимое интерфейса должно быть точно таким же, как и у контроллера интерфейса, который мы хотим вызвать, за исключением того, что мы пишем только интерфейс, а не реализацию. Если есть параметры или возвращаемые значения типа pojo, скопируйте соответствующие классы напрямую. Если их слишком много, вынесите их в отдельный модуль и дальше зависьте от них.

Поскольку в UserController есть только один метод, который мы хотим вызвать, мы можем просто получить его напрямую. В то же время добавьте аннотацию feinClient в интерфейс.

Язык кода:javascript
копировать
package com.lsqingfeng.springcloud.order.client;

import com.lsqingfeng.springcloud.common.base.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @interface: UserFeignClient
 * @description:
 * @author: sh.Liu
 * @date: 2022-03-29 19:10
 */
@Component
@FeignClient(name="userservice")
public interface UserFeignClient {
    /**
     * привет в userController
     * @param name
     * @return
     */
    @GetMapping("hello")
    Result hello(String name);
}

Обратите внимание, что имя параметра в @FeignClient — это имя службы, которую мы хотим вызвать. То есть значение Spring.application.name соответствующего сервиса. Это значение также зарегистрировано для имени в nacos.

4.3 Использование среди потребителей

Как только клиент будет готов, его можно будет использовать так же, как и обычную инъекцию зависимостей. Мы полагаемся на соответствующий клиент в OrderController для завершения вызова интерфейса пользовательского модуля.

Язык кода:javascript
копировать
package com.lsqingfeng.springcloud.order.controller;

import com.lsqingfeng.springcloud.common.base.Result;
import com.lsqingfeng.springcloud.order.client.UserFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @className: OrderController
 * @description:
 * @author: sh.Liu
 * @date: 2022-03-29 17:54
 */
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private UserFeignClient userFeignClient;

    @GetMapping("getOrder")
    public Result getOrder(String orderNo){
        Result result = userFeignClient.hello(orderNo);
        return result;
    }

}

Затем перекомпилируем и запустим проект. При запуске сервиса заказа я обнаружил ошибку.

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderController': Unsatisfied dependency expressed through field 'userFeignClient'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.lsqingfeng.springcloud.order.client.UserFeignClient': Unexpected exception during bean creation; nested exception is java.lang.IllegalStateException: No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?

Эта проблема связана с тем, что SpringCloud Feign больше не использует Ribbon после версии Hoxton.M2 ​​RELEASED, а использует Spring-cloud-loadbalancer, поэтому будет сообщено об ошибке, если Spring-cloud-loadbalancer не будет введен.

Решение:

Добавить зависимость Spring-cloud-loadbalancer

Язык кода:javascript
копировать
<!--loadbalancer -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

Проект снова успешно запущен. Давайте вызовем интерфейс заказа, чтобы увидеть эффект:

Ошибка произошла снова, на этот раз это был 405, и я был готов взорваться. В основном это было вызвано отсутствием аннотаций для параметров при вызове OpenFein. Добавляем @RequestParam в параметры интерфейса openFein

Язык кода:javascript
копировать
package com.lsqingfeng.springcloud.order.client;

import com.lsqingfeng.springcloud.common.base.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @interface: UserFeignClient
 * @description:
 * @author: sh.Liu
 * @date: 2022-03-29 19:10
 */
@Component
@FeignClient(name="userservice")
public interface UserFeignClient {
    /**
     * привет в userController
     * @param name
     * @return
     */
    @GetMapping("/user/hello")
    Result hello(@RequestParam("name") String name);
}

Можно лишь сказать, что это несовершенная часть OpenFeign, и многие аннотации нельзя опустить. Позвоните еще раз. Есть результаты:

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

Итак, вызов OpenFeign реализован. Все, пожалуйста, поторопитесь и поймите. Код загружен в git. Если есть какие-то непонятные части, вы можете скачать код и изучить его.

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose