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. 这种 ...
随机推荐
- cocos2d-x开发: 一切应该从配置文件读取开始
想要做一款完整的游戏,应该从配置文件读取开始.cocos2d-x本身提供了UserDefault来操作xml格式的配置文件,准确的说配置这模块引擎开发者已经考虑到了.但是xml格式包含大量无关的格式信 ...
- HTML基础代码
<!--注释内容,在浏览时不会显示--><!DOCTYPE HTML> <!--声明文档类型--><html> <!--头部内容:--> & ...
- PLSQL数据库无选项问题解决
添加如下ORACLE_HOME和OCI library 添加之后,关闭plsql再打开会出现如下界面: 其中database为空. 我当时也是在环境变量里面配置了TNS_ADMIN的环境变量为:如下 ...
- Oracle服务
oracle服务 参考网址:http://www.oraclejsq.com/article/010100132.html Oracle在window下安装完毕,会安装很多服务,如下图: 1.Orac ...
- 如何设计处优秀的Restful API
只知道遵规循矩的程序员是假程序员,任何技术都是不断发明创造改进的. 如何设计处优秀的Restful API? 盲目跟风,设计糟糕的Resful API = 浪费时间 ! 不啰嗦,直接进入技术主题: ...
- Windows10系统在VMware中安装CentOS7操作系统并实现图形化用户界面Gnome
由于操作系统课程需要,我尝试在windows10环境下安装linux虚拟机,最终采用centOS7和Gnome图形用户界面,在安装和使用过程中出现一些问题,在这里将其记录下来,以便后续查阅. 第一部分 ...
- linux 学习第十六天(Samba配置)
Samba 服务 yum install samba mv smb.conf smb.conf.bak cat smb.conf.bak | grep -v "#" | grep ...
- flAbsPath on /var/lib/dpkg/status failed 解决 Cydia 红字
越狱之后抹掉所有数据,然后再使用 doubleH3lix 越狱成功后,打开 Cydia 会提示如下错误: flAbsPath on /var/lib/dpkg/status failed - real ...
- 【大数据实战】Logstash采集->Kafka->ElasticSearch检索
1. Logstash概述 Logstash的官网地址为:https://www.elastic.co/cn/products/logstash,以下是官方对Logstash的描述. Logstash ...
- C++ —— 类中static和const关键字声明变量的初始化方式总结
在类中声明变量/常量时,经常会用到static.const关键字.对于该变/常量的初始化问题,网上有许多相关文章,但是大多不够完善,或者存在错误.经过实际验证,总结如下: (注明:测试编译平台为VS2 ...