5. Spring Cloud OpenFeign 声明式 WebService 客户端的超详细使用 @目录5. Spring Cloud OpenFeign 声明式 WebService 客户端的超详细使用前言1. OpenFeign 介绍1.1 Feign 和 OpenFeign 区别2. Op
@[toc]
- 对应上一篇学习内容:??? 4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明_ribbon升级到了loadbalancer-CSDN博客
- 对应下一篇学习内容:???
OpenFeign 是什么 ?
OpenFeign 是个声明式
WebService
客户端,使用 OpenFeign 让编写 Web Service客户端更简单。
它的使用方法是 定义一个服务接口,然后在上面添加注解。
OpenFeign 也支持可插拔式的 编码器 和 解码器 。
Spring Cloud 对 OpenFeign 进行了封装使其支持了 Spring MVC 标注注解 和
HttpMessageConverters
。
OpenFeign 可以与 Eureka 和 Ribbon 组合使用以支持负载均衡。
OpenFeign 官网地址: https://github.com/spring-cloud/spring-cloud-openfeign
简单的说:就是一个 Web Service 客户端访问的,转发的一个组件,可以实现 Server 集群的通信,简化 Web Service 客户端 。
Feign:
org.springframework.cloud
spring-cloud-starter-openfeign
OpenFeign:
org.springframework.cloud
spring-cloud-starter-openfeign
需求分析&图解
示意图:
参考 member-service-consumer-80 创建 member-service-consumer-openfeign-80(具体步 骤参考以前)
pom.xml
文件当中,导入相关的 jar 依赖。特别是这里:我们的主角
openFeign
。
org.springframework.cloud
spring-cloud-starter-openfeign
完整的 pom.xml 文件信息:
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">
e-commerce-center
com.rainbowsea
1.0-SNAPSHOT
4.0.0
member-service-consumer-openfeign-80
org.springframework.cloud
spring-cloud-starter-openfeign
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-actuator
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
com.rainbowsea
e_commerce_center-common-api
${project.version}
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
application.yml
进行一些相关的配置信息, 内容如下:
server:
port: 80
spring:
application:
name: member-service-consumer-openfeign-80
# 配置 eureka client 注意,因为这里该模块是作为 client 客户端的角色的,所有要将自己client的信息发送给 Server 当中去的
eureka:
client:
register-with-eureka: true # 表示将自己注册到 Eureka-Server 当中
fetch-registry: true # 表示将信息发送到 Eureka-Server 当中
service-url:
# 表示将自己注册到那个 eureka-server
# defaultZone: http://localhost:9001/eureka
# 将本微服务注册到多个 eureka - server 当中,使用逗号间隔即可
defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9002.com:9002/eureka/
member-service-consumer-openfeign-80
的主启动类,也就是场景启动器。
在:创建包
com.rainbowsea.springcloud
,创建名为
MemberConsumerOpenfeignApplication80
的主启动类,如下图所示:
package com.rainbowsea.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient // 表示作为 Eureka Client 角色
@EnableFeignClients // 启动 OpenFeignClient
public class MemberConsumerOpenfeignApplication80 {
public static void main(String[] args) {
SpringApplication.run(MemberConsumerOpenfeignApplication80.class, args);
}
}
添加主启动类之后,我们可以测试一下,是否成功将该模块
member-service-consumer-openfeign-80
注册到了 Eureka Server 当中去了。
注意:下面的操作就是:是 OpenFeign 的核心内容了。
member-service-consumer-openfeign-80
模块当中创建一个
com.rainbowsea.springcloud.service
包,在该包当中创建一个
MemberFeignService
接口,注意注意是接口
interface
不是类。如下图所示:
package com.rainbowsea.springcloud.service;
import com.rainbowsea.springcloud.entity.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Component
public interface MemberFeignService {
}
然后我们需要将其中,我们
member-service-consumer-openfeign-80
模块是作为 Eureka Client 客户端存在的,这里使用 OpenFeign 简化客户端,我们还需将 ,我们 OpenFeigin(也就是客户端,也就是 Eureka Client ) 想要调用的哪个
provider service(服务器/服务集群)
处理我们的业务,这里我们是
服务集群
,这里我们有两个 privoid service 可以处理我们所需的业务,如下图所受:分别为:
member-service-provider-10000,member-service-provider-10002 这两个服务(这两个服务,是已经相互注册好了,配置为了服务集群了 )
这里我们在
MemberFeignService
接口类上使用
@FeignClient
注解标注,我们这个 OpenFeigin(也就是客户端,也就是 Eureka Client ) 想要调用的哪个
provider service(服务器/服务集群)
处理我们的业务。如下图所示:
package com.rainbowsea.springcloud.service;
import com.rainbowsea.springcloud.entity.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@Component
//这里 MEMBER-SERVICE-PROVIDER 就是 Eureka Server 服务提供方注册的名称
@FeignClient(value = "MEMBER-SERVICE-PROVIDER") // 这个 value 值就是,对应我们想要访问的 provider(提供服务/服务集群)的 name 名称
public interface MemberFeignService {
}
同时我们还需要在
MemberFeignService
接口当中定义一个方法。
注意这个方法,必须必须和你 OpenFeigin(也就是客户端,也就是 Eureka Client ) 想要调用的哪个
provider service(服务器/服务集群)
中的处理对应业务的 哪个方法 ,保持一致(权限修饰符一致,**Http请求方式(包括了所对应的请求映射路径)**一致,参数类型,参数个数一致,返回值类型也是一致的,方法名可以不一致(但强烈建议也保持一致)),所以强烈建议,直接从对应的 provider service 当中复制过来即可。如下图:我们使用的是getMemberById
根据 id 查询的业务处理。我们只需将其方法名复制过来即可。
package com.rainbowsea.springcloud.service; import com.rainbowsea.springcloud.entity.Result; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @Component //这里 MEMBER-SERVICE-PROVIDER 就是 Eureka Server 服务提供方注册的名称 @FeignClient(value = "MEMBER-SERVICE-PROVIDER") // 这个 value 值就是,对应我们想要访问的 provider(提供服务/服务集群)的 name 名称 public interface MemberFeignService { // 注意:这里定义方法-就是远程调用的接口,建议复制过来 /* 1.远程调用的方式是get 2.远程调用的 url http://MEMBER-SERVICE-PROVIDER(注册到服务当中的别名)/member/get/{id} 3.MEMBER-SERVICE-PROVIDER 就是服务提供方法 Eureka Server 注册的服务 4. openfeign 会根据负载均衡决定调用 10000/10002 -默认是轮询 5.因为openfeign 好处是支持了 spring mvc 注解 + 接口解构 6. 想要使用 OPFeign 需要在对应场景启动器的位置配置上: @EnableFeignClients // 启动 OpenFeignClient */ @GetMapping("/member/get/{id}") Result getMemberById(@PathVariable("id") Long id); }
最后,我们在当前
member-service-consumer-openfeign-80
模块也就是我们的 OpenFeigin(也就是客户端,也就是 Eureka Client ) 编写控制器,在
com.rainbowsea.springcloud.controller
包下,编写对应的控制器。如下图所示:
package com.rainbowsea.springcloud.controller;
import com.rainbowsea.springcloud.entity.Result;
import com.rainbowsea.springcloud.service.MemberFeignService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class MemberConsumerFeignController {
// 装配MemberFeignService
@Resource
private MemberFeignService memberFeignService;
@GetMapping("/member/consumer/openfeign/get/{id}")
public Result getMemberById(@PathVariable("id") Long id) {
// 调用接口中的方法
return memberFeignService.getMemberById(id);
}
}
- 特别说明,因为我们的 OpenFeign 就是一个通过
接口+注解的
方式作为Eureka Client 客户端,调用其中 Service 服务器- Openfeign 的使用的特点:
微服务接口+@FeignClient
,使用接口进行解耦(简单的说:就是使用接口调用对应 provider 提供服务的集群)
测试,启动服务器
浏览器输入 : http://localhost/member/consumer/openfeign/get/1
观察访问的 10000/10002 端口的服务是轮询的
@FeignClient(value = "MEMBER-SERVICE-PROVIDER")
// 这个 value 值就是,对应我们想要访问的 provider(提供服务/服务集群)的 name 名称 所以:注意不要将提供注册的名称,写错了
说明 OpenFeign 提供了日志打印功能,可以通过配置来调整日志级别,从面对 OpenFeign 接口的调用情况进行监控和输出。
日志级别:
- NONE: 默认的,不显示任何日志
- BASIC: 仅记录请求方式,URL,响应状态码及执行时间
- HEADERS:除了 BASIC 中定义的信息之外,还有请求和响应的头信息
- FULL: 除了HEADERS 中定义的信息之外,还有请求和响应的正文及元数据
常见的日志级别有 5 种,分别是 error、warn、info、debug、trace
- error:错误日志,指比较严重的错误,对正常业务有影响,需要运维配置监控的;
- warn:警告日志,一般的错误,对业务影响不大,但是需要开发关注;
- info:信息日志,记录排查问题的关键信息,如调用时间、出参入参等等;
- debug:用于开发 DEBUG 的,关键逻辑里面的运行时数据;
- trace:最详细的信息,一般这些信息只记录到日志文件中。
在member-service-consumer-openfeign-80 创建 com.Rainbowsea.springcloud.config.OpenFeignConfig.java 类
package com.rainbowsea.springcloud.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class OpenFeignConfig {
@Bean
public Logger.Level loggerLever() {
// /日志级别指定为 FULL
return Logger.Level.FULL;
}
}
在
member-service-consumer-openfeign-80
模块当中修改
application.yml
进行配置我们是对哪个类进行日志打印信息,以及打印配置的日志信息的
级别
。
logging:
level:
# 对 MemberFeignService 接口调用过程打印信息-Debug
com.rainbowsea.springcloud.service.MemberFeignService: debug
server:
port: 80
spring:
application:
name: member-service-consumer-openfeign-80
# 配置 eureka client 注意,因为这里该模块是作为 client 客户端的角色的,所有要将自己client的信息发送给 Server 当中去的
eureka:
client:
register-with-eureka: true # 表示将自己注册到 Eureka-Server 当中
fetch-registry: true # 表示将信息发送到 Eureka-Server 当中
service-url:
# 表示将自己注册到那个 eureka-server
# defaultZone: http://localhost:9001/eureka
# 将本微服务注册到多个 eureka - server 当中,使用逗号间隔即可
defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9002.com:9002/eureka/
logging:
level:
# 对 MemberFeignService 接口调用过程打印信息-Debug
com.rainbowsea.springcloud.service.MemberFeignService: debug
测试
浏览器: http://localhost/member/consumer/openfeign/get/1
IDEA 后端查看打印的显示的日志信息:
OpenFeign 超时: 我们先来看如下一个问题:
我们模拟网络异常,在
member-service-provider-10000
和
member-service-provider-10002
两个 service 服务提供方当中的
getMemberById
方法,模拟超时 ,这里暂停 5秒。
// 模拟超时 ,这里暂停 5秒
try {
TimeUnit.SECONDS.sleep(5);
} catch (Exception e) {
e.printStackTrace();
}
浏览器访问 http://localhost/member/consumer/openfeign/get/1
测试效果:
浏览器显示: Read timed out executing GET http://MEMBER-SERVICE-PROVIDER/member/get/1
IDEA后端显示: java.net.SocketTimeoutException: Read timed out
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.RetryableException: Read timed out executing GET http://MEMBER-SERVICE-PROVIDER/member/get/1] with root cause
原因分析: OpenFeign 默认超时时间 1 秒钟 ,即等待返回结果 1 秒 ,超过了 1 秒,则会报错。
设置超时时间
说明: 在某些情况下,一个服务调用时间可能要超过 1 秒,就需要重新设置超时时间。
这里我们设置超时时间设置为:
8秒
,而我们模拟的是 5秒,5 秒小于 8 秒,可以还在超时时间的范围内,可以被访问。
对于 OpenFeign 超时时间,我们需要在
application.yaml
文件当中进行配置。
如下图所示:
# OpenFeign 超时
ribbon:
# #设置 feign 客户端超时时间(openFeign 默认支持 ribbon) #指的是建立连接后从服务器读取到可用资源所用的时间,
# #时间单位是毫秒
ReadTimeout: 8000
# #指的是建立连接所用的时间,适用于网络状况正常的情况下,
# #两端连接所用的时间
ConnectTimeout: 8000
server:
port: 80
spring:
application:
name: member-service-consumer-openfeign-80
# 配置 eureka client 注意,因为这里该模块是作为 client 客户端的角色的,所有要将自己client的信息发送给 Server 当中去的
eureka:
client:
register-with-eureka: true # 表示将自己注册到 Eureka-Server 当中
fetch-registry: true # 表示将信息发送到 Eureka-Server 当中
service-url:
# 表示将自己注册到那个 eureka-server
# defaultZone: http://localhost:9001/eureka
# 将本微服务注册到多个 eureka - server 当中,使用逗号间隔即可
defaultZone: http://eureka9001.com:9001/eureka/,http://eureka9002.com:9002/eureka/
logging:
level:
# 对 MemberFeignService 接口调用过程打印信息-Debug
com.rainbowsea.springcloud.service.MemberFeignService: debug
# OpenFeign 超时
ribbon:
# #设置 feign 客户端超时时间(openFeign 默认支持 ribbon) #指的是建立连接后从服务器读取到可用资源所用的时间,
# #时间单位是毫秒
ReadTimeout: 8000
# #指的是建立连接所用的时间,适用于网络状况正常的情况下,
# #两端连接所用的时间
ConnectTimeout: 8000
浏览器输出: http://localhost/member/consumer/openfeign/get/1, 不会出现超时,会轮询访问 10000/10002
当我们在
pom.xml
当中添加了
spring-boot-starter-actuator
的依赖 jar ,就就可以使用该 监控系统了。不需要其他的配置
spring-boot-starter-actuator 是spring boot 程序的监控系统,可以实现健康检查,info 信息等
访问http://localhost:80/actuator 可以看到相关链接,还可以做相关配置。
spring-boot-starter-actuator
访问的语法链接:url地址+自身模块对应的端口号/actuator
。
WebService
客户端,使用 OpenFeign 让编写 Web Service客户端更简单。
微服务接口+@FeignClient
,使用接口进行解耦(简单的说:就是使用接口调用对应 provider 提供服务的集群)
微服务接口+@FeignClient
,使用接口进行解耦(简单的说:就是使用接口调用对应 provider 提供服务的集群)
spring-boot-starter-actuator
访问的语法链接:
url地址+自身模块对应的端口号/actuator
。
“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”