Spring Boot - 如何在微服务之间进行通信?

Posted

技术标签:

【中文标题】Spring Boot - 如何在微服务之间进行通信?【英文标题】:Spring Boot - how to communicate between microservices? 【发布时间】:2018-11-03 11:45:23 【问题描述】:

我目前正在开发一个 Spring Boot 微服务项目。我已经创建了服务,并且每个服务都单独运行。有了这个,我需要一些服务来与其他服务进行通信。我怎样才能做到这一点?

我看到一些关于此的博客,它们使用 Netflix、Eureka 云服务器来实现这一点。有没有什么方法可以在我的本地环境中实现这一点而不使用云服务器?

【问题讨论】:

你可以在本地运行 Eureka,但是,Eureka 不是关于微服务之间的通信,而是关于发现其他微服务。在你发现一个微服务之后,如何与它通信由你来决定,Eureka 并没有告诉你如何去做。这意味着您的问题非常广泛,理论上您甚至可以根据需要通过 TCP 以二进制莫尔斯电码进行通信。 【参考方案1】:

当然可以。 微服务只是 REST 服务。 您需要了解 REST-Services 是如何工作的。 之后只需用 Spring-boot 编写 2 个微服务(2 个 Rest-Services:生产者服务和消费者服务),让它们在不同的服务器端口下运行,从另一个调用消费者服务,就是这样:你有你的微服务。 现在这是编写微服务的原始方式。

要让它们进化,您需要添加一些“魔法”(不是火箭科学),例如使用 Ribbon 在“生产者服务”的两个实例之间分配负载。

你可以使用一个发现服务,它只是一个带有注解 @EnableEurekaServer 的 spring-boot 应用程序(你需要在你的 pom 中添加适当的依赖项) 现在将注释@EnableDiscoveryClient 添加到您的第一个(原始)微服务到主类中,并在两者的application.properties(或application.yml)中指向您的eureka-service的defaultZone,启动您的eureka-service(发现服务)和2 个微服务:将在发现服务上注册。当然现在你不需要在消费者服务中硬编码生产者服务的http地址了。 看看这个tutorial

于 2018 年 11 月 21 日格林威治标准时间 12:41 编辑

假设您的第一个(微不足道的)微服务(纯粹的休息服务)在您的 PC 上的 8091 端口下运行。

在您的第二个(普通)微服务的控制器中,您使用 RestTemplate.getForEntity(url,responseType,uriVariables) 调用您的第一个服务,就像链接教程中的示例一样:

ResponseEntity<CurrencyConversionBean> responseEntity = 
   new RestTemplate().getForEntity(
        "http://localhost:8091/currency-exchange/from/from/to/to", CurrencyConversionBean.class,  uriVariables);

在哪里 url:您的第一个(微)(休息)服务的 url。 responseType:等待响应的对象的类/类型。 uriVariables:是一个包含 URI 模板变量的映射。

【讨论】:

【参考方案2】:

微服务之间有不同的通信方式。但是使用哪一个:取决于用例。

    Api call:这是使用 RestTemplateFeignClient 等对其他服务进行实际的 rest api 调用。
ResponseType obj=  new RestTemplate().getForObject(URL, ResponseType.class, params);
    但是如果用例不同怎么办,例如,您有 customer 微服务和 orders 微服务都使用单独的数据库。您在 orders 数据库中也有 customer name 和其他详细信息。一旦客户更新了他们的姓名,您还必须更新订单数据库中的详细信息。如何做到这一点。通过API call?那么如果 account 微服务也需要此更新怎么办。所以 Rest api 将是一个开销。在这个用例中,我们可以像 RabbitMQ 一样使用 MessageQueues。客户微服务将创建一个客户更新事件,任何对此感兴趣的微服务都可以订阅。

通过像 RabbitMQ 这样的消息队列进行通信

Spring.io rabbit mq guide

【讨论】:

我很想知道从不同的微服务中获取数据。我想从产品微服务中获取客户的名字。在我的情况下,产品服务必须调用订单服务来获取订单 ID,根据订单 ID,我需要调用客户微服务来获取客户名称。就我而言,不仅是一个文件,它还包含许多文件来获取这样的数据。你会就问题提出任何解决方案吗?【参考方案3】:

这取决于您的选择、您希望在服务之间进行同步通信还是异步通信的天气。 对于同步服务,您可以使用以下任一第三方工具:

    Hashcorp 领事 Netflix Eureka [您可以使用 Netflix RIBBON 进行客户端负载平衡] NATS 等等

对于异步,您可以使用以下消息传递解决方案:

    Redis [使用列表/流] ActiveMQ RabitMQ 卡夫卡 NATS 等等

【讨论】:

【参考方案4】:

正如@g00glen00b 在 cmets 中提到的,Eureka 不用于微服务之间的通信。它用于服务发现。 我知道有两种方式可以与其他微服务通信:

    休息模板 Feign 客户端

RestTemplate 使用起来非常简单。它不需要配置。

例如

   ResponseType obj=  new RestTemplate().getForObject(URL, ResponseType.class, params);

url - 网址

responseType - 返回值的类型

params- 扩展模板的变量

Spring Doclink供您参考

【讨论】:

【参考方案5】:

这篇文章似乎很旧,但我会尝试与寻找相同问题解决方案的新开发人员分享我的经验。

您将需要这些库: 祖尔网关, 尤里卡发现服务器, 尤里卡发现客户端, Rest 模板(如果您开发 REST API)。

Gateway 可以管理 Spring Boot 微服务应用的所有路由。仅使用注释和 application.properties,您就可以设置整个服务器。您不需要编写单行 Java 代码。

发现服务器在新的微服务启动或停止时监听事件。它注册了所有使用 @EnableEurekaClient 注释的微服务。

Rest Template 是一个成熟的 Rest 客户端库,在自定义 http 请求和 http 响应配置方面非常灵活。例如,您可以使用客户端 http 拦截器配置来拦截 http 请求和响应以添加更多数据,或记录信息等。

我的 GitHub 页面上有开源微服务应用程序。免费分发、分叉、克隆、商业化.. 没有欲望:-)

一切顺利..

【讨论】:

你能帮我分享一下 GitHub 链接吗【参考方案6】:

虽然 REST 很熟悉,因此易于实现,但如果您需要更灵活和类似 Java 的通信,Spring 的 (Spring-to-Spring) HTTP Invoker 可能是一个不错的选择。

如果您需要基于 HTTP 的远程处理,Spring 的 HTTP 调用程序是一个不错的选择 还要依赖Java序列化。它共享基本 带有 RMI 调用程序的基础设施,仅使用 HTTP 作为传输。笔记 HTTP 调用程序不仅限于 Java 到 Java 远程处理,而且 也适用于客户端和服务器端的 Spring。 (后者也 适用于非 RMI 接口的 Spring 的 RMI 调用程序。)

https://docs.spring.io/spring/docs/2.5.x/reference/remoting.html https://www.baeldung.com/spring-remoting-http-invoker

【讨论】:

【参考方案7】:
@Autowired
    private RestTemplate restTemplate;

@Autowired
    private EurekaClient eurekaClient;


@RequestMapping("/dashboard/myself")
    public EmployeeInfo findme(@PathVariable Long myself) 
        Application application = eurekaClient.getApplication(employeeSearchServiceId);
        InstanceInfo instanceInfo = application.getInstances().get(0);
        String url = "http://" + instanceInfo.getIPAddr() + ":" + instanceInfo.getPort() + "/" + "employee/find/" + myself;
        System.out.println("URL" + url);
        EmployeeInfo emp = restTemplate.getForObject(url, EmployeeInfo.class);
        System.out.println("RESPONSE " + emp);
        return emp;
    

来源: https://dzone.com/articles/microservices-communication-service-to-service

【讨论】:

包括代码在内的答案应至少包含解释代码如何工作以及为什么回答问题的说明。此外,必须改进代码格式。我建议对后一个问题进行编辑,请修复代码描述部分。【参考方案8】:

我们也可以使用在 Netflix Feign 项目之上开发的https://cloud.spring.io/spring-cloud-openfeign/reference/html/。

【讨论】:

虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review

以上是关于Spring Boot - 如何在微服务之间进行通信?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Spring Boot/Spring Cloud 实现微服务应用

在 Spring Boot 中使用 FeignClient 进行同步 Rest API 调用

Spring - 如何在微服务之间自动传递http标头

如何在 Spring Boot 中模拟数据库连接以进行测试?

如何构建spring boot

Spring Boot 微服务 - 依赖