SpringCloud进击 | 二浅出:服务消费者(Ribbon+REST)【Finchley版本】

1.前言

上一节 我们实践的是 Spring Cloud 的服务注册与发现。在微服务架构中,业务基本上都会被拆分成一个独立的服务,服务与服务的通讯是基于 http restful 的。

Spring Cloud 有两种服务调用方式,一种是 Ribbon + RestTemplate,另一种是 Feign。Ribbon是一个负载均衡客户端,可以很好的控制HTTP和TCP的一些行为。我们这章就来讲讲它 -- Ribbon,如何使用 Eureka 服务注册中心,搭建一个简单的服务端注册服务,客户端调用服务的案例。

上一节:SpringCloud进击 | 一浅出:服务注册与发现(Eureka)【Finchley版本】

 

2.论点

我们先提出几个论点,后面来论证:

1) 假设服务提供者有一个方法,可以根据服务消费者的请求,获取到该方法的输出。
2) 假设服务消费者具备负载均衡功能,可以根据服务消费者的请求获取到不同服务提供者的相同输出(可变参数除外)。

 

3.准备

三个角色:

  • 服务注册中心:wei-eureka-server,端口 8090,启动一个(无需修改,正常启动)
  • 服务提供者:wei-service-provider,分别以 8010、8011 端口启动一次,获得两个实例的集群(无需修改,正常启动)
  • 服务消费者:Ribbon,创建一个 wei-consumer-ribbon 模块,端口 8020(新建应用)

基于上一节的实践和创建好的工程,分别启动 服务注册中心:wei-eureka-server,启动 服务提供者:wei-service-provider,这都是上一节的成果。然后这节我们创建一个服务消费者(wei-consumer-ribbon),用来发送请求消费服务提供者提供的接口。

 

4.进击

4.1.创建服务消费者(Ribbon)

项目上新建一个模块:wei-consumer-ribbon,用来实现 Ribbon + RestTemplate。创建方法与上一节创建模块过程类似。但在Dependencies选择依赖时需要注意以下:

a) 选择左侧的 Web 后,这里需要钩上 Web 项
b) 选择左侧的 Cloud Discovery 后,这里需要钩上 Eureka Discovery 项
c) 选择左侧的 Cloud Routing后,这里需要钩上 Ribbon 项

最后点 Finish 按钮后,一个模块就自动生成了。

 

4.1.1.POM依赖

其 pom.xml 全内容如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.wei</groupId>
    <artifactId>wei-consumer-ribbon</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>wei-consumer-ribbon</name>
    <description>服务消费者(ribbon + rest)(Finchley版本)</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!--客户端负载均衡-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

</project>

 

4.1.2.配置服务消费者

编写配置 application.yml

server:
  port: 8020
spring:
  application:
    name: wei-consumer-ribbon    # 指定进行服务注册时该服务的名称,服务与服务之间相互调用一般都是根据这个name
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8090/eureka/    # 指定进行服务注册的地址
  • spring.application.name 属性:指定微服务应用的名称,后续在调用的时候只需要使用该名称就可以进行服务间的访问。
  • eureka.client.serviceUrl.defaultZone 属性:对应服务注册中心的配置内容,指定服务注册中心的位置。
  • server.port 属性:为了在本机上测试区分服务提供方和服务注册中心,使用 server.port 属性设置不同的端口。

这里,我们指定的服务注册中心地址为 http://localhost:8090/eureka/,服务名称为:wei-consumer-ribbon,程序端口为:8020

 

4.1.3.编写Service

package com.wei.service.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class DemoRibbonService {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 创建一个新接口用来消费服务提供者提供的接口
     * 用程序名替代了具体的url地址,在ribbon中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的url替换掉服务名
     */
    public String getDemoRibbonServiceName(String name) {
        String result = restTemplate.getForObject("http://wei-service-provider/demo/info?name=" + name, String.class);
        result += "[Ribbon + REST]";
        System.out.println(result);
        return result;
    }
}

使用 RestTemplate 来消费 wei-consumer-ribbon 服务的 "/demo/info" 接口。这里,用程序名替代了具体的URL地址,在 Ribbon 中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的URL替换掉服务名。

 

4.1.4.编写Controller

package com.wei.controller.demo;

import com.wei.service.demo.DemoRibbonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoRibbonController {

    /**
     * 自动装载错误提示,不用管这个,运行的时候会被正确注入
     */
    @Autowired
    private DemoRibbonService demoRibbonService;

    @RequestMapping(value = {"/ribbon/demo/info", "/demo/info"})
    public String getDemoRibbonServiceName(@RequestParam String name) {
        return demoRibbonService.getDemoRibbonServiceName(name);
    }
}

写一个 controller,在 controller 中用调用 Service 的 getDemoRibbonServiceName() 方法。这里配置两个路由,请求输出效果是一样的。

 

4.1.5.编写启动类

package com.wei;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
public class WeiConsumerRibbonApplication {

    public static void main(String[] args) {
        SpringApplication.run(WeiConsumerRibbonApplication.class, args);
    }

    /**
     * 注解@Bean,向程序注入一个Bean
     * 注解@LoadBalanced,开启RestTemplate的负载均衡功能
     * 初始化RestTemplate,用来发起 REST 请求
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

在工程的启动类中,通过 @LoadBalanced 注解,开启 RestTemplate 负载均衡功能。

最后,Run 一下这个启动类。

 

5.测试

好了,一切准备就绪。我们就来验证一下吧。

 

5.1.验证服务消费者

浏览器反复请求URL:http://localhost:8020/demo/info?name=tester

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010[Ribbon + REST]

浏览器可始终打印上述内容。到此,论点1已经论证完成,结果与预期一致。

 

5.2.验证Ribbon负载均衡

但是,Ribbon 它是一个基于 HTTP 和 TCP 的客户端负载均衡器。而上述操作并没有展现这种效果,所以,我们接下来就来论证上面的论点2:假设服务消费者具备负载均衡功能,可以根据服务消费者的请求获取到不同服务提供者的相同输出(可变参数除外)。

其实只需要简单的操作就可以达到目的,就是修改一下服务提供者的端口号(由8010改为8011),然后再Run一下其启动类,以新开一个服务提供者实例。

新开一个服务提供者实例步骤如下(后继的章节不再复述):

【应用实例多开-1】

a) 在IDEA上点击Application右边的下三角,弹出选项后,点击 Edit Configuration

【应用实例多开-2】

b) 打开配置后,选择需要的 Application 后,将默认的 Single instance only (单实例) 的钩去掉
c) 修改 application 文件的属性 server.port 的端口号,再运行程序启动类。如果想要多开,则每个实例需要配置不同的端口号

当端口为8011的实例跑起来之后,我们再去 Spring Eureka 的服务注册信息面板,看一看8011实例有没有被 Eureka 所发现并注册进去。

【Eureka Server】

嗯,看来一切正常。

现在有两个服务提供者,相当于一个小小的 Service 集群。那我们来验证一下 Ribbon 的负载均衡:

浏览器反复请求URL:http://localhost:8020/demo/info?name=tester 或者 http://localhost:8020/ribbon/demo/info?name=tester

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8010[Ribbon + REST]

Hi,tester,我是服务,我被调用了,服务名为:wei-service-provider,端口为:8011[Ribbon + REST]

我们可以看到浏览器也在8010和8011端口之间,也就是这个小的 Service 服务提供者集群之间交替打印输出内容。

 

到此,Ribbon 的负载均衡功能被实现且验证成功。论点2成立。


下一节,请继续关注:SpringCloud进击 | 三浅出:服务消费者(Feign)【Finchley版本】

 

5.总结

5.1.案例中有三个角色:

    服务注册中心、服务提供者、服务消费者

5.2.它们的工作流:

  1. 启动服务注册中心
  2. 服务提供者生产服务并注册到服务中心 
  3. 服务消费者从服务中心中获取服务并使用

5.3.此时的架构图:


本节源码:https://github.com/itanping/wei-springcloud/tree/master/chapter02-ribbon


 

6.物语

SpringCloud进击 | 一浅出:服务注册与发现(Eureka)【Finchley版本】
SpringCloud进击 | 二浅出:服务消费者(Ribbon+REST)【Finchley版本】
SpringCloud进击 | 三浅出:服务消费者(Feign)【Finchley版本】
SpringCloud进击 | 四浅出:断路器与容错(Hystrix)【Finchley版本】
SpringCloud进击 | 五浅出:服务网关 - 路由(Zuul Router)【Finchley版本】
SpringCloud进击 | 六浅出:服务网关 - 过滤器(Zuul Filter)【Finchley版本】
SpringCloud进击 | 七浅出:配置中心(Git配置与更新)【Finchley版本】
SpringCloud进击 | 一深入:配置中心(服务化与高可用)【Finchley版本】
SpringCloud进击 | 二深入:配置中心(消息总线)【Finchley版本】
SpringCloud进击 | 三深入:服务链路跟踪(Spring Cloud Sleuth)【Finchley版本】
SpringCloud进击 | 四深入:服务链路跟踪(Sleuth+Zipkin+RabbitMQ整合)【Finchley版本】
SpringCloud进击 | 五深入:断路器监控(Hystrix Dashboard)【Finchley版本】
SpringCloud进击 | 六深入:断路器聚合监控(Hystrix Turbine)【Finchley版本】
SpringCloud进击 | 七深入:高可用的服务注册中心【Finchley版本】

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值