SpringCloud基础教程04-服务调用之ribbon

概述

在第二篇文章SpringCloud服务调用之Feign中,我们介绍了SpringCloud中使用feign进行服务调用的案例。当时还介绍了feign是基于ribbon的。

这一篇,我们就来看看通过原生的ribbon是怎么进行服务调用的。

官方文档:https://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-ribbon

Ribbon is a client side load balancer which gives you a lot of control over the behaviour of HTTP and TCP clients. Feign already uses Ribbon, so if you are using @FeignClient then this section also applies.

ribbon可以实现服务调用和负载均衡,而feign集成了ribbon。

也就是说:feign是基于ribbon的,ribbon的调用可以理解是SpringCloud原生的服务调用。

注:这一篇,我们基于上一篇SpringCloud服务注册之Consul中的consul来实现这么一个demo。

需要:consul、service-producer服务(引入consul)、service-consumer服务(引入consul和ribbon)

版本:SpringBoot 2.0.7.RELEASE与SpringCloud Finchely.RELEASE


一、service-producer

服务生产者与上一节相同,需要引入consul-discovery:

        <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    </properties>

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

        <!-- 引入consul用于服务注册与发现 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        <!-- 健康监控 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </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>

配置文件:

server:
  port: 8200
spring:
  application:
    name: service-producer
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        register: true
        instance-id: ${spring.application.name}:${server.port}
        service-name: ${spring.application.name}
        port: ${server.port}

启动类添加@EnableDiscoveryClient注解:

package com.example.serviceproducer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceProducerApplication {

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

}

测试接口:

package com.example.serviceproducer;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "producer")
public class HelloAction {

    @GetMapping(value = "hello/{name}")
    public String hello(@PathVariable String name) {
        return "Hello " + name + ", this is response from hello by service-producer.";
    }
}

启动服务后,测试一下:

ribbon-producer.png

二、service-consumer

服务消费者需要引入consul-discoverynetflix-ribbon:

        <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    </properties>

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

        <!-- 引入consul用于服务注册与发现 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        <!-- 健康监控 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- 引入ribbon -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </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>

配置文件与service-producer基本相同:

server:
  port: 8201
spring:
  application:
    name: service-consumer
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        register: true
        service-name: ${spring.application.name}
        instance-id: ${spring.application.name}:${server.port}
        port: ${server.port}

同样在启动类上添加@EnableDiscoveryClient注解。

下面就有所不同了,还需要注入一个RestTemplate的Bean实例——这个类来自spring-boot-starter-web包:

package com.example.serviceconsumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableDiscoveryClient
public class ServiceConsumerApplication {

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

    /**
     * 注入RestTemplate Bean并开启负载均衡
     * @return
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

注:也可以不采用注入而在使用的时候直接new RestTemplate()

看一下我编写的测试接口:

package com.example.serviceconsumer;

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;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping(value = "consumer")
public class ConsumerAction {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping(value = "test")
    public String test(String name) {
        // 利用RestTemplate,直接请求对应的service-name/request
        String producerRes = restTemplate.getForObject("http://service-producer/producer/hello/" + name, String.class);
        String res = "service-consumer服务调用service-producer服务,hello接口返回数据:" + producerRes;
        System.out.println(res);
        return res;
    }
}

上面的示例中,使用了restTemplate.getForObject("http://service-producer/producer/hello/" + name, String.class);来调用服务service-producer的路径为producer/hello/{name}的接口。

扩展:ribbon/feign/http比较

与普通的HTTP请求比较:HTTP请求使用http://ip:port/path的方式请求,而ribbon则使用http://service-name/path的方式。

与feign请求比较:

@FeignClient(name = "service-provider")
public interface HelloRemote {

    @GetMapping(value = "hello/{name}")
    public String hello(@PathVariable("name") String name);
}

feign是使用@FeignClient来声明式地声明一个与被调用服务接口相同的接口,然后直接调用这个接口。而ribbon是直接通过路径调用。


四、测试

启动service-consumer后,看一下consul:

ribbon-consul.png

测试consumer服务调用producer服务:

ribbon-consumer.png

至此,基于ribbon进行服务调用的示例已经完成。具体可以参考下面地址的源码。


五、项目源码

https://github.com/laolunsi/spring-cloud-examples/tree/master/04-ServiceConsumeRibbon


参考

  1. 方志朋-服务消费者(rest+ribbon)(Finchley版)https://blog.csdn.net/forezp/article/details/81040946

欢迎大家关注我的公众号:猿生物语,搜索关键词或扫码:


export1571065791508.jpg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容