【微服务-Ribbon】Ribbon+RestTemplate的服务通信实现方式之代码模式

前面我们了解了负载均衡的作用以及负载均衡的一些负载策略,这篇我们来看一下,在微服务(SpringCloud)架构中,如何来实现服务间的高可用通信。

我们先来了解下SpringCloud自带的RestTemplate对象,RestTemplate 对象是Spring Cloud 封装的 RESTful 通信对象,它封装了基于 HTTP 协议的操作,通过简单的API便可发起 HTTP 请求并自动处理响应。RestTemplate 天然与 Ribbon 兼容,两者配合可以极大简化服务间通信过程。Ribbon + RestTemplate 提供了两种开发模式:代码模式注解模式

下面我们来看一下两种开发模式的具体代码实现。

一、代码模式

代码模式是指通过纯 Java 代码实现微服务间通信,虽然工作中代码模式很少使用,但它却是理解 Ribbon+RestTemplate 最直观的途径,所以我们先来看他。该模式使用主要分为两个阶段:

1、创建服务提供者

服务提供者也就是请求的实际处理者,也是标准的SpringBoot工程,利用controller对外暴露RESTful API供服务消费者调用。

(1)创建provider-service微服务

【微服务-Ribbon】Ribbon+RestTemplate的服务通信实现方式之代码模式

其中pom.xml要确保引用了web和nacos-discovery两个依赖。

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

    <groupId>com.alibaba.cloud</groupId>

    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>

</dependency>

(2)在application.yml中调整微服务与Nacos的通信配置

spring:

  application:

    name: provider-service #应用/微服务名字

  cloud:

    nacos:

      discovery:

        server-addr: 106.14.221.171:8848 #nacos服务器地址

        username: nacos #用户名密码

        password: nacos

server:

  port: 80

(3)创建ProviderController,通过controller控制器对外暴露接口

package com.example.providerservice.controller;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

public class ProviderController {

    @GetMapping("/provider/msg")

    public String sendMessage(){

        return "the message from provider service!";

    }

}

到这里,我们的服务提供者已经开发完毕(这里只是做个案例,实际业务肯定没这么简单,大家理解就行)。服务提供者就是标准的 Spring Cloud 微服务,向 Nacos 进行注册的同时对外暴露 msg 接口并返回一段静态文本,并没有任何与 Ribbon 相关的内容。确实,Ribbon 与 RestTemplate 应出现在服务消费者,而非提供者一端。

(4)微服务多节点模拟

为了演示效果,我们要准备五台虚拟机来模拟:

Ip 端口 用途
192.168.3.1 8848 Nacos注册中心实例部署(非集群)
192.168.3.2 80 服务提供者实例1
192.168.3.3 80 服务提供者实例2
192.168.3.4 80 服务提供者实例3
192.168.3.5 80 服务消费者实例1

这里,我们通过一台Nacos实例来做注册中心,服务提供者分别部署三台,来模拟负载均衡效果。

  • 将上面的服务提供者工程,打包成jar包。
  • 将jar包上传到192.168.3.2、192.168.3.3、192.168.3.4三台服务器上,并使用java命令启动微服务。
java -jar provider-service.jar
  • 节点启动后,我们可以在Nacos注册中心中看一下微服务启动注册情况。
【微服务-Ribbon】Ribbon+RestTemplate的服务通信实现方式之代码模式
  • 单独访问任意节点的接口,都可以看到返回的相同文本。
http://192.168.3.2/provider/msg

http://192.168.3.3/provider/msg

http://192.168.3.4/provider/msg

【微服务-Ribbon】Ribbon+RestTemplate的服务通信实现方式之代码模式

到这里,服务提供者的开发告一段落。

2、创建服务消费者

服务消费者说白了就是服务的使用方,我们需要在服务消费者内置 Ribbon+RestTemplate 实现服务间高可用通信。

(1)创建服务消费者工程

【微服务-Ribbon】Ribbon+RestTemplate的服务通信实现方式之代码模式pom.xml确保要引用以下三个依赖:

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

    <groupId>com.alibaba.cloud</groupId>

    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>

</dependency>

<dependency>

    <groupId>org.springframework.cloud</groupId>

    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>

    <version>${spring-cloud-alibaba.version}</version>

</dependency>

starter-netflix-ribbon 就是通过 Spring Boot Starter 向当前微服务工程集成 Ribbon,无须做其他额外配置。与此同时,用于 RESTful 通信的 RestTemplate 对象已被集成到 starter-web 模块,无须额外依赖。

(2)配置application.yml

这里除微服务id与服务提供者不同外,其他都一样

spring:

  application:

    name: customer-service #应用/微服务名字

  cloud:

    nacos:

      discovery:

        server-addr: 106.14.221.171:8848 #nacos服务器地址

        username: nacos #用户名密码

        password: nacos

server:

  port: 80

(3)声明RestTemplate

利用 Spring Java Config 方式声明 RestTemplate。在 ConsumerServiceApplication 类中新增以下声明代码

@SpringBootApplication

public class ConsumerServiceApplication {

    //Java Config声明RestTemplate对象

    //在应用启动时自动执行restTemplate()方法创建RestTemplate对象,其BeanId为restTemplate。

    @Bean

    public RestTemplate restTemplate(){

        return new RestTemplate();

    }

    public static void main(String[] args) {

        SpringApplication.run(ConsumerServiceApplication.classargs);

    }

}

(4)创建消费controller,并通过Ribbon+RestTemplate实现负载均衡通信

package com.example.consumerservice.controller;

...

@RestController

public class ConsumerController {

    private Logger logger = LoggerFactory.getLogger(ConsumerController.class);

    //注入 Ribbon 负载均衡器对象

    //在引入 starter-netflix-ribbo n后在 SpringBoot 启动时会自动实例化 LoadBalancerClient 对象。

    //在 Controlle 使用 @Resource 注解进行注入即可。

    @Resource

    private LoadBalancerClient loadBalancerClient;

    @Resource

    //将应用启动时创建的 RestTemplate 对象注入 ConsumerController

    private RestTemplate restTemplate;

    @GetMapping("/consumer/msg")

    public String getProviderMessage() {

        //loadBalancerClient.choose()方法会从 Nacos 获取 provider-service 所有可用实例,

        //并按负载均衡策略从中选择一个可用实例,封装为 ServiceInstance(服务实例)对象

        //结合现有环境既是从192.168.3.2:80、192.168.3.3:80、192.168.3.4:80三个实例中选择一个包装为ServiceInstance

        ServiceInstance serviceInstance = loadBalancerClient.choose("provider-service");

        //获取服务实例的 IP 地址

        String host = serviceInstance.getHost();

        //获取服务实例的端口

        int port = serviceInstance.getPort();

        //在日志中打印服务实例信息

        logger.info("本次调用由provider-service的" + host + ":" + port + " 实例节点负责处理" );

        //通过 RestTemplate 对象的 getForObject() 方法向指定 URL 发送请求,并接收响应。

        //getForObject()方法有两个参数:

        //1. 具体发送的 URL,结合当前环境发送地址为:http://192.168.3.2:80/provider/msg

        //2. String.class说明 URL 返回的是纯字符串,如果第二参数是实体类, RestTemplate 会自动进行反序列化,为实体属性赋值

        String result = restTemplate.getForObject("http://" + host + ":" + port + "/provider/msg", String.class);

        //输出响应内容

        logger.info("provider-service 响应数据:" + result);

        //向浏览器返回响应

        return "consumer-service 响应数据:" + result;

    }

}

(5)消费者服务打包部署

将上述消费者工程打包成jar包后部署至192.168.3.5服务器上,并执行命令运行起来。

运行后可以到Nacos注册中心查看注册情况:

【微服务-Ribbon】Ribbon+RestTemplate的服务通信实现方式之代码模式

(6)运行效果

部署和注册好之后,我们就可以调用消费者接口来看一下服务情况,日志如下:

本次调用由 provider-service 的 192.168.3.2:80 实例节点负责处理

consumer-service 获得数据:the message from provider service!

本次调用由 provider-service 的 192.168.3.3:80 实例节点负责处理

consumer-service 获得数据:the message from provider service!

本次调用由 provider-service 的 192.168.3.4:80 实例节点负责处理

consumer-service 获得数据:the message from provider service!

本次调用由 provider-service 的 192.168.3.2:80 实例节点负责处理

consumer-service 获得数据:the message from provider service!

从上面输出日志可以看出,服务提供者有三个节点,默认是按照轮巡的方式按顺序逐个调用的。如果发生某个服务提供者宕机,Nacos心跳机制就会检测并将其剔除,这样我们继续调用消费者来获取服务者提供的服务时,消费者就不会再向宕机的节点发起请求了。有兴趣的大家可以试试。

以上便是代码模式的处理过程,它清晰的说明了Ribbon的执行过程,先从 Nacos 获取可用服务提供者实例信息,再通过 RestTemplate.getForObject() 向该实例发起 RESTful 请求完成处理。

也许你也察觉到了代码模式使用复杂,需要自己获取可用实例 IP、端口信息,再拼接 URL 实现服务间通信,那有没有更简单的办法呢?答案是肯定的,利用 @LoadBalanced 注解可自动化实现这一过程。

关于注解模式实现的步骤,我们下一篇再接着聊。

欢迎关注公众号:服务端技术精选。欢迎点赞、关注、转发


原文始发于微信公众号(服务端技术精选):【微服务-Ribbon】Ribbon+RestTemplate的服务通信实现方式之代码模式

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/258923.html

(0)
服务端技术精选的头像服务端技术精选

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!