概述

在前面的文章中,我们讲了使用Eureka作为服务注册中心,在服务启动后,各个微服务会将自己注册到Eureka server。那么服务之间是如何调用?又是如何进行负载均衡的呢?本文讲讲服务之间调用及负载均衡Ribbon。

目前,在Spring cloud 中服务之间通过restful方式调用有两种方式restTemplate+Ribbon

feign

从实践上看,采用feign的方式更优雅(feign内部也使用了ribbon做负载均衡)。

本文使用如下的项目实例来分别演示这两种写法。hello服务,读取数据库,返回信息

world服务,返回信息

helloworld服务,调用了hello服务和world服务(restTemplate+Ribbon方式)

helloworldfeign服务,调用了hello服务和world服务(feign方式)

项目之间关系.png

本文项目代码:springcloud-demo

如何理解客户端Ribbon

zuul也有负载均衡的功能,它是针对外部请求做负载,那客户端ribbon的负载均衡又是怎么一回事?

客户端ribbon的负载均衡,解决的是服务发起方(在Eureka注册的服务)对被调用的服务的负载,比如我们查询商品服务要调用显示库存和商品明细服务,通过商品服务的接口将两个服务组合,可以减少外部应用的请求,比如手机App发起一次请求即可,可以节省网络带宽,也更省电。

ribbon是对服务之间调用做负载,是服务之间的负载均衡,zuul是可以对外部请求做负载均衡。

Ribbon负载均衡.png

hello服务与world服务

hello服务

Git项目代码:hello

pom.xml

org.springframework.boot

spring-boot-starter

org.springframework.boot

spring-boot-starter-test

test

org.springframework.boot

spring-boot-starter-web

org.springframework.cloud

spring-cloud-starter-eureka

org.springframework.boot

spring-boot-starter-data-jpa

1.5.4.RELEASE

mysql

mysql-connector-java

5.1.31

runtime

org.springframework.boot

spring-boot-starter-actuator

1.5.6.RELEASE

org.springframework.cloud

spring-cloud-dependencies

Dalston.SR2

pom

import

启动类HelloApplication:package com.example.hello;import com.example.hello.model.Info;import com.example.hello.repository.InfoRepository;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.boot.CommandLineRunner;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.context.annotation.Bean;@EnableDiscoveryClient@SpringBootApplicationpublic class HelloApplication {    private static final Logger log= LoggerFactory.getLogger(HelloApplication.class);    public static final String KEY="Database";    public static final String VALUE="MYSQL FROM BILLJIANG";    public static void main(String[] args) {

SpringApplication.run(HelloApplication.class, args);

}    @Bean

public CommandLineRunner initDatabase(InfoRepository repository){        return (args) -> {

repository.save(new Info(KEY,VALUE));

};

}

}

入口类HelloController:package com.example.hello.controller;import com.example.hello.HelloApplication;import com.example.hello.model.HelloMessage;import com.example.hello.model.Info;import com.example.hello.repository.InfoRepository;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.client.ServiceInstance;import org.springframework.cloud.client.discovery.DiscoveryClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestControllerpublic class HelloController {    @Autowired

private DiscoveryClient discoveryClient;    @Autowired

private InfoRepository infoRepository;    @GetMapping("/")    public String home(){        return "hello";

}    @GetMapping("/message")    public HelloMessage getMessage() {

HelloMessage helloMessage = new HelloMessage();

helloMessage.setName(getLocalInstanceInfo());

helloMessage.setMessage(getInfoFromDatabase());        return helloMessage;

}    private String getLocalInstanceInfo() {

ServiceInstance serviceInstance = discoveryClient.getLocalServiceInstance();        return serviceInstance.getServiceId() + ":" + serviceInstance.getHost() + ":" + serviceInstance.getPort();

}    private String getInfoFromDatabase() {

List infoList = infoRepository.findByName(HelloApplication.KEY);        for (Info info : infoList) {            return info.toString();

}        return "(no database info)";

}

}

配置文件application.yml:#随机端口server:

port: 0#服务注册中心eureka:

client:

service-url:

default-zone: http://localhost:8761/eureka

instance:

instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}#数据源spring:

application:

name: hello

datasource:

url: jdbc:mysql://127.0.0.1:3306/${{MYSQL_DATABASE}:foodb}

username: ${{MYSQL_USERNAME}:root}

password: ${{MYSQL_PASSWORD}:billjiang}

testWhileIdle: true

validationQuery: SELECT 1

jpa:

show-sql: true

hibernate:

ddl-auto: update

naming-strategy: org.hibernate.cfg.ImprovedNamingStrategy

properties:

hibernate:

dialect: org.hibernate.dialect.MySQL5Dialect

zipkin:

base-url: http://127.0.0.1:9411

其他类略,请参照源码:

world

world服务与hello服务类似,不过没有连接数据库

项目代码:world

helloworld调用hello服务和world服务

采用restTemplate+Ribbon调用服务。

项目代码:helloworld

启动类HelloworldApplication:

配置restTemplate的Beanpackage com.example.helloworld;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.context.annotation.Bean;import org.springframework.web.client.RestTemplate;@SpringBootApplication@EnableDiscoveryClientpublic class HelloworldApplication {    public static void main(String[] args) {

SpringApplication.run(HelloworldApplication.class, args);

}    @Bean

@LoadBalanced

RestTemplate restTemplate() {        return new RestTemplate();

}

}

入口类HelloworldController:package com.example.helloworld.controller;import com.example.helloworld.model.HelloMessage;import com.example.helloworld.model.HelloworldMessage;import com.example.helloworld.model.WorldMessage;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.client.loadbalancer.LoadBalanced;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;import org.springframework.web.client.RestTemplate;/**

* @author billjiang 475572229@qq.com

* @create 17-8-22

*/@RestControllerpublic class HelloworldController {    private static final Logger log = LoggerFactory.getLogger(HelloworldController.class);    private static final String HELLO_SERVICE_NAME = "hello";    private static final String WORLD_SERVICE_NAME = "world";    @Autowired

private RestTemplate restTemplate;    @GetMapping("/")    public String home() {        return "hello world";

}    @GetMapping("/message")    public HelloworldMessage getMessage() {

HelloMessage hello = getMessageFromHelloService();

WorldMessage world = getMessageFromWorldService();

HelloworldMessage helloworld = new HelloworldMessage();

helloworld.setHello(hello);

helloworld.setWord(world);

log.debug("Result helloworld message:{}", helloworld);        return helloworld;

}    private HelloMessage getMessageFromHelloService() {

HelloMessage hello = restTemplate.getForObject("http://hello/message", HelloMessage.class);

log.debug("From hello service : {}.", hello);        return hello;

}    private WorldMessage getMessageFromWorldService() {

WorldMessage world = restTemplate.getForObject("http://world/message", WorldMessage.class);

log.debug("From world service : {}.", world);        return world;

}

}

测试:

helloworldfeign调用hello服务和world服务

feign方式调用服务,项目代码参考:helloworldfeign

pom.xml引入feignx

org.springframework.cloud

spring-cloud-starter-feign

配置启动类注解:package com.example.helloworldfeign;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.cloud.netflix.feign.EnableFeignClients;@SpringBootApplication@EnableDiscoveryClient@EnableFeignClientspublic class HelloworldFeignApplication {    public static void main(String[] args) {

SpringApplication.run(HelloworldFeignApplication.class, args);

}

}

被调用接口HelloServicepackage com.example.helloworldfeign.service;import com.example.helloworldfeign.model.HelloMessage;import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;/**

* @author billjiang 475572229@qq.com

* @create 17-8-23

*/@FeignClient(value="hello")public interface HelloService {    @GetMapping("/message")    HelloMessage hello();

}

被调用接口WorldServicepackage com.example.helloworldfeign.service;import com.example.helloworldfeign.model.WorldMessage;import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;/**

* @author billjiang 475572229@qq.com

* @create 17-8-23

*/@FeignClient(value="world")public interface WorldService {    @GetMapping("/message")    WorldMessage world();

}

入口类HelloworldController:package com.example.helloworldfeign.controller;import com.example.helloworldfeign.model.HelloMessage;import com.example.helloworldfeign.model.HelloworldMessage;import com.example.helloworldfeign.model.WorldMessage;import com.example.helloworldfeign.service.HelloService;import com.example.helloworldfeign.service.WorldService;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.RestController;/**

* @author billjiang 475572229@qq.com

* @create 17-8-23

*/@RestControllerpublic class HelloworldController {    private static final Logger log = LoggerFactory.getLogger(HelloworldController.class);    private static final String HELLO_SERVICE_NAME = "hello";    private static final String WORLD_SERVICE_NAME = "world";    @Autowired

private HelloService helloService;    @Autowired

private WorldService worldService;    @GetMapping("/")    public String home() {        return "hello world";

}    @GetMapping("/message")    public HelloworldMessage getMessage() {

HelloMessage hello = helloService.hello();

WorldMessage world = worldService.world();

HelloworldMessage helloworld = new HelloworldMessage();

helloworld.setHello(hello);

helloworld.setWord(world);

log.debug("Result helloworld message:{}", helloworld);        return helloworld;

}

}

为了更好的地查看效果,hello服务和world服务可以启动多个实例,并把调用实例的ip和端口输出来。

作者:billJiang

链接:https://www.jianshu.com/p/7ca91139dca5

feign调用service_微服务之间的调用(Ribbon与Feign)相关推荐

  1. 从0到1学SpringCloud——08 通过fegin实现微服务之间请求调用

    目录 一.前言 1.关于Fegin 2.注意事项 3.POM依赖 二.编码实现 1.启动类 2.创建openfeign接口 3.Controller代码 4.回调工厂 三.文件配置 1.Feign接口 ...

  2. feign调用多个服务_Spring Cloud 快速入门系列之feign–微服务之间的调用

    我们将一个大的应用拆成多个小的服务之后,紧接着的一个问题就是,原本都在一个项目里,方法我可以随便调用,但是拆开后,原来的方法就没法直接调用了,这时候要怎么办? Spring Cloud提供了feign ...

  3. Spring Cloud【Finchley】实战-03订单微服务与商品微服务之间的调用

    文章目录 Spring Cloud[Finchley]专栏 概述 HTTP方式之RestTemplate 方式一 (直接使用restTemplate访问URL,url写死) 方式二 (使用LoadBa ...

  4. Spring Cloud之微服务之间相互调用、如何让一个微服务调用另外一个微服务

    在使用微服务架构中,可能遇到一些业务情况会涉及服务之间相互调用,下面通过一个简单的demo给大家演示下,演示的是oms服务需要调用ump服务. 代码如下: 1.oms服务提供者 主要是这个注解: @E ...

  5. JHipster技术栈定制 - 基于UAA的微服务之间安全调用

    本文通过代码实例演示如何通过UAA实现微服务之间的安全调用. uaa: 身份认证服务,同时也作为被调用的资源服务.服务端口9999. microservice1: 调用uaa的消费者服务,服务端口80 ...

  6. mysql 间接引用_微服务之间安全调用 by UAA

    本文通过代码实例演示如何通过UAA实现微服务之间的安全调用. uaa: 身份认证服务,同时也作为被调用的资源服务.服务端口9999. microservice1: 调用uaa的消费者服务,服务端口80 ...

  7. SpringCloud微服务之间如何调用接口

    一.通过Nacos 进行微服务的注册与发现 (provider(接口调用者)和comsumer(接口提供者)两个微服务都要进行以下前3步) 1.在微服务对应pom.xml中配置Nacos客户端的pom ...

  8. eureka自我保护时间_spring cloud中微服务之间的调用以及eureka的自我保护机制详解...

    上篇讲了spring cloud注册中心及客户端的注册,所以这篇主要讲一下服务和服务之间是怎样调用的 基于上一篇的搭建我又自己搭建了一个客户端微服务: 所以现在有两个微服务,我们所实现的就是微服务1和 ...

  9. 微服务之间的调用方式RestTemplate和FeignClient

    SpringCloud服务间的调用有两种方式:RestTemplate和FeignClient.不管是什么方式,他都是通过REST接口调用服务的http接口,参数和结果默认都是通过jackson序列化 ...

最新文章

  1. go监听mysql事件更新,有没有一种方法可以“监听”数据库事件并实时更新页面?...
  2. python爬虫(五)_urllib2:urlerror和httperror
  3. 6、处理大数据对象(CLOB 数据小说+BLOG 数据图片,电影,音乐)
  4. 新一代才子原创歌曲--《伤心日记》- 孔朝
  5. 从您的计算机移除此产品,解决office提示“此操作只对目前安装的产品有效”的方法...
  6. CPU可以跑多快?地球到火星的距离告诉你!
  7. QT学习笔记之MySql如何计算两个时间段相隔的天数
  8. 如何在 Laravel 中 “规范” 的开发验证码发送功能
  9. python脚本根据cookies自动登录网站_为爬虫获取登录cookies:使用万能钥匙 Selenium 搞定一切登录...
  10. python的设计哲学_Python的设计哲学--zen of Python
  11. 如何进行普通家用无线路由器的性能测试?
  12. ElasticSearch问题求解:master not discovered yet: have discovered
  13. RStudio入门使用常见问题(1)
  14. openwrt路由器接华为E3372(E8372)网卡实现4G转有线和WIFI
  15. 【python-Unet】计算机视觉~舌象舌头图片分割~机器学习(三)
  16. 两年工作经验面试经验以及面试题分享
  17. QQ2012 Beta1 (支持窗口合并、20人视频)
  18. java计时器_Java 计时器
  19. 古汉语常用字字典_掌握了音序或部首查字法,就会查字典了?不,差得远着呢!...
  20. Friday the Thirteenth 黑色星期五

热门文章

  1. 小米9震撼发布!米粉大呼价格太良心 2999元起稳了吗?
  2. 苹果官网再度开售iPhone SE:这是在为新品清库存了?
  3. 拳王虚拟项目公社:通过信息差获免费取虚拟资源,网上怎么售卖教程赚钱
  4. 收集SQLite中的时间日期函数[ZT]
  5. 小米手机,测试时应用图标不能更改,还出现偶尔应用版本还原
  6. rm ,rm -rf , rm -f,rm -r 以及rm 命令的其他参数命令
  7. c语言读取excel表格_利用pandas处理excel表格
  8. 路强 java 百度云,解决 Tried to download(403): 。。。zopfli-v2.0.2
  9. python数据文件输入输出_python 文件输入与输出
  10. 我的一些学习经验:概述