Spring Cloud(三):服务提供与调用 Eureka【Finchley 版】
Spring Cloud(三):服务提供与调用 Eureka【Finchley 版】
上一篇文章我们介绍了 Eureka 服务注册中心的搭建,这篇文章介绍一下如何使用 Eureka 服务注册中心,搭建一个简单的服务端注册服务,客户端去调用服务使用的案例。
案例中有三个角色:服务注册中心、服务提供者、服务消费者,其中服务注册中心就是我们上一篇的 Eureka 单节点启动既可。
流程如下:
- 启动注册中心
- 服务提供者生产服务并注册到服务中心中
- 消费者从服务中心中获取服务并执行
服务提供者
我们假设服务提供者有一个 hello()
方法,可以根据传入的参数,提供输出 “hello xxx + 当前时间” 的服务。
POM 包配置
创建一个基本的 Spring Boot 应用,命名为eureka-producer
,在 pom.xml 中添加如下配置:
1 |
<dependency> |
配置文件
application.yml 配置如下
1 |
spring: |
通过spring.application.name
属性,我们可以指定微服务的名称后续在调用的时候只需要使用该名称就可以进行服务的访问。eureka.client.serviceUrl.defaultZone
属性对应服务注册中心的配置内容,指定服务注册中心的位置。为了在本机上测试区分服务提供方和服务注册中心,使用server.port
属性设置不同的端口。
启动类
保持默认生成的即可, Finchley.RC1 这个版本的 Spring Cloud 已经无需添加@EnableDiscoveryClient
注解了。(那么如果我引入了相关的 jar 包又想禁用服务注册与发现怎么办?设置eureka.client.enabled=false
)
@EnableDiscoveryClient
is no longer required. You can put aDiscoveryClient
implementation on the classpath to cause the Spring Boot application to register with the service discovery server.
Spring Cloud - @EnableDiscoveryClient
1 |
@SpringBootApplication |
Controller
提供 hello 服务
1 |
@RestController |
启动工程后,就可以在注册中心 Eureka 的页面看到 EUERKA-PRODUCER 服务。
我们模拟一个请求试一下 Producer 能否正常工作
http://localhost:8000/hello/?name=windmt
1 |
Hello, windmt Fri Apr 13 18:36:36 CST 2018 |
OK, 直接访问时没有问题的,到此服务提供者配置就完成了。
服务消费者
创建服务消费者根据使用 API 的不同,大致分为三种方式。虽然大家在实际使用中用的应该都是 Feign,但是这里还是把这三种都介绍一下吧,如果你只关心 Feign,可以直接跳到最后。
三种方式均使用同一配置文件,不再单独说明了
1 |
spring: |
使用 LoadBalancerClient
从LoadBalancerClient
接口的命名中,我们就知道这是一个负载均衡客户端的抽象定义,下面我们就看看如何使用 Spring Cloud 提供的负载均衡器客户端接口来实现服务的消费。
POM 包配置
我们先来创建一个服务消费者工程,命名为:eureka-consumer
。pom.xml 同 Producer 的,不再赘述。
启动类
初始化RestTemplate
,用来发起 REST 请求。
1 |
@SpringBootApplication |
Controller
创建一个接口用来消费 eureka-producer 提供的接口:
1 |
@RequestMapping("/hello") |
可以看到这里,我们注入了LoadBalancerClient
和RestTemplate
,并在hello
方法中,先通过loadBalancerClient
的choose
方法来负载均衡的选出一个eureka-producer
的服务实例,这个服务实例的基本信息存储在ServiceInstance
中,然后通过这些对象中的信息拼接出访问服务调用者的/hello/
接口的详细地址,最后再利用RestTemplate
对象实现对服务提供者接口的调用。
另外,为了在调用时能从返回结果上与服务提供者有个区分,在这里我简单处理了一下,name+="!"
,即服务调用者的 response 中会比服务提供者的多一个感叹号(!)。
访问 http://localhost:9000/hello/?name=windmt 以验证是否调用成功
1 |
Hello, windmt! Fri Apr 13 18:44:55 CST 2018 |
Spring Cloud Ribbon
之前已经介绍过 Ribbon 了,它是一个基于 HTTP 和 TCP 的客户端负载均衡器。它可以通过在客户端中配置 ribbonServerList 来设置服务端列表去轮询访问以达到均衡负载的作用。
当 Ribbon 与 Eureka 联合使用时,ribbonServerList 会被 DiscoveryEnabledNIWSServerList 重写,扩展成从 Eureka 注册中心中获取服务实例列表。同时它也会用 NIWSDiscoveryPing 来取代 IPing,它将职责委托给 Eureka 来确定服务端是否已经启动。
POM 包配置
将之前的 eureka-consumer 工程复制一份,并命名为 eureka-consumer-ribbon。
pom.xml 文件还用之前的就行。至于 spring-cloud-starter-ribbon,因为我使用的 Spring Cloud 版本是 Finchley.RC1,spring-cloud-starter-netflix-eureka-client 里边已经包含了 spring-cloud-starter-netflix-ribbon 了。
1 |
<dependency> |
启动类
修改应用主类,为RestTemplate
添加@LoadBalanced
注解
1 |
@LoadBalanced |
Controller
修改 controller,去掉LoadBalancerClient
,并修改相应的方法,直接用 RestTemplate
发起请求
1 |
@GetMapping("/") |
可能你已经注意到了,这里直接用服务名eureka-producer
取代了之前的具体的host:port
。那么这样的请求为什么可以调用成功呢?因为 Spring Cloud Ribbon 有一个拦截器,它能够在这里进行实际调用的时候,自动的去选取服务实例,并将这里的服务名替换成实际要请求的 IP 地址和端口,从而完成服务接口的调用。
访问 http://localhost:9001/hello/?name=windmt 以验证是否调用成功
1 |
Hello, windmt! Fri Apr 13 22:24:14 CST 2018 |
也可以通过启动多个 eureka-producer 服务来观察其负载均衡的效果。
Spring Cloud Feign
在实际工作中,我们基本上都是使用 Feign 来完成调用的。我们通过一个例子来展现 Feign 如何方便的声明对 eureka-producer 服务的定义和调用。
POM 包配置
创建一个基本的 Spring Boot 应用,命名为eureka-producer-feign
,在 pom.xml 中添加如下配置:
1 |
<dependency> |
启动类
在启动类上加上@EnableFeignClients
1 |
@EnableFeignClients |
Feign 调用实现
创建一个 Feign 的客户端接口定义。使用@FeignClient
注解来指定这个接口所要调用的服务名称,接口中定义的各个函数使用 Spring MVC 的注解就可以来绑定服务提供方的 REST 接口,比如下面就是绑定 eureka-producer 服务的/hello/
接口的例子:
1 |
@FeignClient(name = "eureka-producer") |
此类中的方法和远程服务中 Contoller 中的方法名和参数需保持一致。
这里有几个坑,后边有详细说明。
Controller
修改 Controller,将 HelloRemote 注入到 controller 层,像普通方法一样去调用即可
1 |
@RequestMapping("/hello") |
通过 Spring Cloud Feign 来实现服务调用的方式非常简单,通过@FeignClient
定义的接口来统一的声明我们需要依赖的微服务接口。而在具体使用的时候就跟调用本地方法一点的进行调用即可。由于 Feign 是基于 Ribbon 实现的,所以它自带了客户端负载均衡功能,也可以通过 Ribbon 的 IRule 进行策略扩展。另外,Feign 还整合的 Hystrix 来实现服务的容错保护,这个在后边会详细讲。(在 Finchley.RC1 版本中,Feign 的 Hystrix 默认是关闭的。参考 Spring Cloud OpenFeign 和 Disable HystrixCommands For FeignClients By Default)。
在我的 IDEA 里,这里会有错误提示,如下
这个其实不用管,运行的时候会被正确注入。如果嫌这个提示烦,可以在HelloRemote
这个接口上边加@Component
注解。
访问 http://localhost:9002/hello/windmt 以验证是否调用成功
1 |
Hello, windmt! Sat Apr 14 01:03:56 CST 2018 |
踩坑记录
问题一:not have available server
1 |
com.netflix.client.ClientException: Load balancer does not have available server for client: eureka-producer |
这个问题刚开始困扰了我好长时间,最后发现原来是因为我没加入 eureka-client 这个依赖,只加了 spring-boot-starter-web 和 spring-cloud-starter-openfeign。只有后两者的话,启动的时候其实是不会有任何异常被抛出的,
但是如果细心地查看了启动 log 的话,其中有这么一条可以看出实际上确实是没有获取到任何服务的
1 |
c.netflix.loadbalancer.BaseLoadBalancer : Client: eureka-producer instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=eureka-producer,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null |
所以,要想使用 Feign,至少需要以下三个依赖
- spring-boot-starter-web
- spring-cloud-starter-openfeign
- spring-cloud-starter-netflix-eureka-client
问题二:Request method ‘POST’ not supported
1 |
feign.FeignException: status 405 reading HelloRemote#hello(String); content: |
HelloRemote
中的代码是这样的,出现上边的异常
1 |
@GetMapping("/hello/") |
改成这样,还是同样的异常
1 |
@RequestMapping(value = "/hello/", method = RequestMethod.GET) |
再改,这次 OK 了
1 |
@GetMapping("/hello/") |
这个问题挺奇葩的的,不加@RequestParam
就变成了 POST 请求,不论我是用@GetMapping
还是method = RequestMethod.GET
,也是无语了。
至于怎么想到的加了个@RequestParam(value = "name")
,说来话长。一开始我没加 eureka-client 依赖,也没加@RequestParam
注解,一启动就报异常:
1 |
Caused by: java.lang.IllegalStateException: PathVariable annotation was empty on param 0. |
所以就加了@RequestParam
,算是歪打正着吧。
至于为什么出现这个 GET 变 POST 的情况,个人猜测应该是当参数没有被@RequestParam
注解修饰时,会自动被当做 request body 来处理。只要有 body,就会被 Feign 认为是 POST 请求,所以整个服务是被当作带有 request parameter 和 body 的 POST 请求发送出去的。
负载均衡
以上三种方式都能实现负载均衡,都是以轮询访问的方式实现的。这个以大家常用的 Feign 的方式做一个测试。
以上面 eureka-producer 为例子修改,将其中的 controller 改动如下:
1 |
@RestController |
打包启动
1 |
// 打包 |
访问 http://localhost:9002/hello/windmt 进行测试。在不断的测试下去会发现两种结果交替出现
1 |
[1]Hello, , windmt Sun Apr 15 19:37:15 CST 2018 |
这说明两个服务中心自动提供了服务均衡负载的功能。如果我们将服务提供者的数量在提高为 N 个,测试结果一样,请求会自动轮询到每个服务端来处理。
相关阅读
Spring Cloud(一):服务治理技术概览
Spring Cloud(二):服务注册与发现 Eureka
Spring Cloud(三):服务提供与调用 Eureka
Spring Cloud(四):服务容错保护 Hystrix
Spring Cloud(五):Hystrix 监控面板
Spring Cloud(六):Hystrix 监控数据聚合 Turbine
Spring Cloud(七):配置中心(Git 版与动态刷新)
Spring Cloud(八):配置中心(服务化与高可用)
Spring Cloud(九):配置中心(消息总线)
Spring Cloud(十):服务网关 Zuul(路由)
Spring Cloud(十一):服务网关 Zuul(过滤器)
Spring Cloud(十二):分布式链路跟踪(Sleuth 与 Zipkin)
示例代码:GitHub
参考
Spring Cloud 构建微服务架构:服务消费(基础)【Dalston 版】
Spring Cloud 构建微服务架构:服务消费(Ribbon)【Dalston 版】
Spring Cloud 构建微服务架构:服务消费(Feign)【Dalston 版】
springcloud(三):服务提供与调用
Spring Cloud OpenFeign
Disable HystrixCommands For FeignClients By Default
Feign 使用 Hystrix 无效原因及解决方法
spring cloud-Feign 使用中遇到的问题总结
- 本文作者: Yibo
- 本文链接: https://windmt.com/2018/04/15/spring-cloud-3-service-producer-and-consumer/
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!
Spring Cloud(三):服务提供与调用 Eureka【Finchley 版】的更多相关文章
- spring cloud(三)服务提供与调用
服务提供 我们假设服务提供者有一个hello方法,可以根据传入的参数,提供输出“hello xxx,this is first messge”的服务 1.pom包配置 创建一个springboot项目 ...
- Spring Cloud 微服务六:调用链跟踪Spring cloud sleuth +zipkin
前言:随着微服务系统的增加,服务之间的调用关系变得会非常复杂,这给运维以及排查问题带来了很大的麻烦,这时服务调用监控就显得非常重要了.spring cloud sleuth实现了对分布式服务的监控解决 ...
- 玩转Spring Cloud之服务注册发现(eureka)及负载均衡消费(ribbon、feign)
如果说用Spring Boot+Spring MVC是开发单体应用(或单体服务)的利器,那么Spring Boot+Spring MVC+Spring Cloud将是开发分布式应用(快速构建微服务)的 ...
- Spring Cloud(三):声明式调用
声明式服务调用 前面在使用spring cloud时,通常都会利用它对RestTemplate的请求拦截来实现对依赖服务的接口调用,RestTemplate实现了对http的请求封装处理,形成了一套模 ...
- Spring Cloud之服务注册中心搭建Eureka Server服务注册中⼼
Spring Cloud并不与Spring MVC类似是一个开源框架,而是一组解决问题的规范(个人理解).解决哪些问题呢?如下: 1)服务管理:⾃动注册与发现.状态监管 2)服务负载均衡 3)熔断 4 ...
- Spring Cloud微服务实践之路- Eureka Server 中的第一个异常
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER ...
- Spring Cloud(四):服务容错保护 Hystrix【Finchley 版】
Spring Cloud(四):服务容错保护 Hystrix[Finchley 版] 发表于 2018-04-15 | 更新于 2018-05-07 | 分布式系统中经常会出现某个基础服务不可用 ...
- Spring Cloud(一):服务治理技术概览【Finchley 版】
Spring Cloud(一):服务治理技术概览[Finchley 版] 发表于 2018-04-14 | 更新于 2018-05-07 | Spring Cloud Netflix 是 Spr ...
- Spring Cloud微服务系列文,服务调用框架Feign
之前博文的案例中,我们是通过RestTemplate来调用服务,而Feign框架则在此基础上做了一层封装,比如,可以通过注解等方式来绑定参数,或者以声明的方式来指定请求返回类型是JSON. 这种 ...
随机推荐
- Gradle Goodness: Copy Files with Filtering
Gradle Goodness: Copy Files with Filtering Gradle's copy task is very powerful and includes filterin ...
- Spring coud微服务框架具体实现关键说明
搭建一个微服务,考虑的问题涉及到运维,数据管理,性能,并发等方方面面.项目中使用Spring coud 搭建微服务,从技术选型,到技术实现都要全方面考虑服务化的问题.下面简单总结下搭建过程用的技术说明 ...
- 编程开发之--Oracle数据库--存储过程在out参数中使用光标(3)
在本系列学习随笔中的第2节我们留下了2个问题,我们现在讨论在out参数中使用光标. 1.要在out参数中使用光标,我们需要申明一个包的结构,包的结构分为包头和包体,包头只负责申明,包体只负责实现.包头 ...
- 编程开发之--Oracle数据库--存储过程和存储函数(2)
上一小结我们简单介绍了存储过程和存储函数,对存储过程和存储函数有了一个基本的了解,接下来介绍在java程序中如何调用我们创建的存储过程和存储函数 1.在应用程序中调用我们的存储过程 创建一个简单的Ja ...
- PyCharm 2018最新激活码通用
通用:Window.Mac.Ubantu都稳定有效,关键是这种激活方式不会产生其他影响 缺点:需要修改hosts文件 **1.修改hosts文件**将 0.0.0.0 account.jetbrain ...
- MySQL->导出/导入资料[20180521]
MySQL 导出 INTO OUTFILE将资料导出至文件中 mysqldump工具导出资料和数据结构,并且可以针对数据库.数据表.索引的结构. INTO OUTFILE测试 ...
- 一次JVM内存调优过程
项目中,有个同事写的JOB,使用到查询数据库大量历史协议数据(大概300W左右),由于对存放数据的list或map没有做“用完即时声明释放”. 导致此Jar部署在windows service后,进程 ...
- vue-cli3详细config配置
const path = require('path') module.exports = { publicPath: './', // vueConf.baseUrl, // 根域上下文目录 // ...
- python--基本类型之元组
tuple(元组): 定义和创建和作用: 元组--只读列表,只可以被查询,不能被修改.所以,列表的切片操作同样适用与元组. 元组写在小括号(())里,元素之间用逗号隔开. 虽然元组的元素不可改变,但他 ...
- 20155202 20155222 信息安全技术概论实验一 PGP的使用
20155202 信息安全技术概论实验一 PGP的使用 实验原理 一.PGP简介 在现代社会里,电子邮件和网络上的文件传输已经成为生活的一部分.邮件的安全问题也就突出了,大家都知道在互联网上传输的数据 ...