В предыдущем случае мы уже построили базовую архитектуру Spring Cloud. На данный момент существует три основных сервиса. Служба Nacos в настоящее время служит нашим центром регистрации, службой пользователей и службой заказов. В предыдущей главе мы успешно зарегистрировали службу пользователя и заказали ее в Nacos, а также смоделировали управление экземплярами службы с помощью Nacos в случае развертывания на нескольких узлах.
Центр регистрации служб является основным компонентом управления на основе служб. Он аналогичен роли служб каталогов. Он в основном используется для хранения информации о службах, например, о поставщиках. url нить、Информация о маршруте и т. д.。Служить Регистрационный центр находитсямикросервисыАрхитектура Один из самых основных объектов в。
Центр регистрации можно назвать «адресной книгой» в микросервисах Архитектура.,он записывает Служитьи Служить Отношения сопоставления адресов。существоватьраспределенныйАрхитектурасередина,Служить зарегистрируется здесь,Когда Служить нужно позвонить другому Служить,Просто зайдите сюда, чтобы найти адрес Служить.,Позвоните.
Простое понимание таково: когда нет центра регистрации, для вызовов между службами должен быть известен конкретный адрес вызывающей службы (жестко заданный ip:port). Чтобы изменить адрес развертывания, вам необходимо изменить адрес, указанный в вызове. В центре регистрации каждой службе необходимо знать только имя службы (мягкое кодирование) при звонке другим, и адрес будет вызываться через центр регистрации для получения конкретного адреса службы на основе имени службы.
Основные функции регистрационного центра
Обычно, когда мы развертываем микросервисы, каждый узел развертывает несколько из них. Когда службы вызывают друг друга, они вызываются через имя службы в центре регистрации. Когда служба выходит из строя, центр регистрации может уведомить потребителя и выбрать доступный узел. звонить, тем самым гарантируя доступность услуги в наибольшей степени.
В эпоху одиночных приложений, если мы хотим выполнить вызовы между нашими различными службами, мы обычно используем для этого классы инструментов, связанные с Http. Однако с появлением микросервисов и увеличением количества служб продолжение использования классов инструментов Http будет необходимо. несомненно, будет огромной проблемой. Это увеличивает нашу рабочую нагрузку и недостаточно элегантно. SpringCloud OpenFeign предоставляет нам клиент декларативного вызова служб. Использование OpenFeign может упростить вызовы между службами.
Что именно умеет OpenFeign:
Еще следует отметить, что на самом деле существует разница между openFeign и feign. Проще говоря, feign обычно используется старой версией Springcloud. Позже она больше не поддерживается, поэтому был выпущен openfeign, и некоторые варианты использования были оптимизированы. . Вы также можете проверить подробные различия в Интернете.
Сначала мы добавляем несколько интерфейсов в сервисы userservice и orderservice. Удобно наблюдать за результатами звонка.
Давайте сначала интегрируем несколько классов унифицированной инкапсуляции результатов, упомянутых ранее, в общий модуль. Если вам это не совсем понятно, вы можете найти мою предыдущую статью: «Унифицированная инкапсуляция результатов SpringBoot». Основные категории следующие:
Затем мы создаем UserController в userservice. Сначала просто разработайте интерфейс.
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 и разрабатываем интерфейс.
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);
}
}
Запустите две программы и давайте протестируем эти два интерфейса.
пользовательский интерфейс:
интерфейс заказа:
Прежде всего, позвольте мне объяснить, что OpenFeign не принадлежит системе SpringCloud Alibaba. Это независимая техническая архитектура. Из каталога SpringCloud мы также видим, что на самом деле она находится на том же уровне, что и SpringCloud Alibaba. Но это не влияет на его использование в архитектуре SpringCloud Alibaba, и он полностью совместим в использовании.
Функция самого OpenFein на самом деле заключается в вызове между сервисами. Конечно, такой вызов можно осуществлять и другими способами. Например, dubbo в системе SpringCloud Alibaba сам осуществляет RPC-вызовы и существовал до появления SpringCloud. был активен в течение длительного времени, поэтому в области вызова сервисов мы можем использовать OpenFeign или dubbo, но, по моим наблюдениям, OpenFeign все еще используется чаще. Dubbo часто используется вместе с Zookeeper для выполнения распределенных вызовов RPC. Если позже у нас будет время, мы также интегрируем dubbo для реализации вызовов между сервисами.
Хорошо, теперь, когда общее введение завершено, давайте реализуем небольшое требование: orderservice вызывает интерфейс userservice через OpenFeign.
Потому что все наши зависимости управляются единообразно в родительском модуле. Теперь нам нужно использовать связанные зависимости SpringCloud, поэтому добавьте их:
<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>
Полный пом выглядит следующим образом:
<?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.
<!--openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
После того как зависимости готовы, мы добавляем аннотацию к классу запуска сервиса заказа: @EnableFeignClients.
Затем мы создаем пакет специально для размещения симулируемого клиентского интерфейса. Просто назовите его клиентом. Затем создайте внутри него интерфейс. Пользователь Фигн Клиент. Содержимое интерфейса должно быть точно таким же, как и у контроллера интерфейса, который мы хотим вызвать, за исключением того, что мы пишем только интерфейс, а не реализацию. Если есть параметры или возвращаемые значения типа pojo, скопируйте соответствующие классы напрямую. Если их слишком много, вынесите их в отдельный модуль и дальше зависьте от них.
Поскольку в UserController есть только один метод, который мы хотим вызвать, мы можем просто получить его напрямую. В то же время добавьте аннотацию feinClient в интерфейс.
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.
Как только клиент будет готов, его можно будет использовать так же, как и обычную инъекцию зависимостей. Мы полагаемся на соответствующий клиент в OrderController для завершения вызова интерфейса пользовательского модуля.
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
<!--loadbalancer -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
Проект снова успешно запущен. Давайте вызовем интерфейс заказа, чтобы увидеть эффект:
Ошибка произошла снова, на этот раз это был 405, и я был готов взорваться. В основном это было вызвано отсутствием аннотаций для параметров при вызове OpenFein. Добавляем @RequestParam в параметры интерфейса openFein
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. Если есть какие-то непонятные части, вы можете скачать код и изучить его.