OpenFeign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求。
Spring Cloud OpenFeign以将OpenFeign集成到Spring Boot应用中的方式。首先利用了OpenFeign的声明式方式定义Web服务客户端;其次还更进一步,通过集成Ribbon或Eureka实现负载均衡的HTTP客户端。
OpenFeign 组件的前身是 Netflix Feign 项目。后来 Feign 项目被贡献给了开源组织,才有了今天使用的 Spring Cloud OpenFeign 组件。
OpenFeign 提供了一种声明式的远程调用接口,它可以简化远程调用的编程体验。
在项目启动阶段,OpenFeign 框架会发起一个主动的扫包流程,从指定的目录下扫描并加载所有被 @FeignClient 注解修饰的接口。
OpenFeign 会针对每一个 FeignClient 接口生成一个动态代理对象。
FeignProxyService,这个代理对象在继承关系上属于 FeignClient 注解所修饰的接口的实例。
这个动态代理对象会被添加到 Spring 上下文中,并注入到对应的服务里,也就是图中的 LocalService 服务。
LocalService 会发起底层方法调用。实际上这个方法调用会被 OpenFeign 生成的代理对象接管,由代理对象发起一个远程服务调用,并将调用的结果返回给 LocalService。
Feign底层是ribbon
Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netf1ixRib5实现。通过 Spring C1oud的封装,可以让我们轻松地将面向服务的REST模版请求自动转換成客户端负载均衡的服务调用。轮询hash权重.
简单的说 Ribbon就是 netfix公司的一个开源项目,主要功能是提供客户端负载均衡算法和服务调用。 Ribbon客户端组件提供了一套完善的配置项,比如连接超时,重试等。在 Spring Cloud构建的微服务系统中, Ribbon作为服务消费者的负载均衡器,有两种使用方式,一种是和 Resttemplate相结合,另一种是和 Openfeign相结合。 openfelgn已经默认集成了 Ribbon,关于 Openfeign的内容将会在下一章进行详细讲解。 Ribbon有很多子模块,但很多模块没有用于生产环境
Openfeign快速入门
Provider端
.yml
server:
port: 8080
spring:
application:
name: provider-server #应用名称
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
User(消费端)
server:
port: 8081
spring:
application:
name: user-server #应用名称
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka
#设置超时时间
ribbon:
ReadTimeout: 3000 # 3秒
ConnectTimeout: 3000 #连接服务的超时时间
OpenFeign调用参数处理(重点)
@PathVariable注解:获取url中的数据
解决映射名称不一致问题(提交请求参数的action的形参名称不一致,使用@RequestParam注解解析)
Feign传参确保消费者和提供者的参数列表一致包括返回值方法签名要一致
1.通过URL传参数,GET请求,参数列表使用@PathVariable (“”)
2.如果是GET请求,每个基本参数必须加回 @Requestparam(“”)
3.如果是posT请求,而且是对象集合等参数,必须加@ Requestbody或者@ Requestparam
provider-service端
@RestController
public class ParamController {
//url传参
@GetMapping("param/{name}/{age}")
public String param(@PathVariable("name") String name,@PathVariable("age") int age){
System.out.println("姓名: "+name+" 年龄 "+age);
return "姓名: "+name+" 年龄 "+age;
}
@GetMapping("getParam")
public String getParam(@RequestParam(required = false) String name){
System.out.println("姓名: "+name);
return "姓名: "+name;
}
@GetMapping("twoParam")
public String twoParam(@RequestParam(required = false) String name,@RequestParam(required = false)int age){
System.out.println("姓名: "+name+" 年龄 "+age);
return "姓名: "+name+" 年龄 "+age;
}
@PostMapping("oneObject")
public String oneObject(@RequestBody User user){
System.out.println(user.toString());
return user + "";
}
}
User-service端
@FeignClient(value = "provider-server") //提供者的应用名称
public interface UserProviderFeign {
@GetMapping("provider")
public String provider();
@GetMapping("param/{name}/{age}")
public String paramUrl(@PathVariable("name") String name, @PathVariable("age") int age);
@GetMapping("getParam")
public String getParam(@RequestParam(required = false) String name);
@GetMapping("twoParam")
public String twoParam(@RequestParam(required = false) String name,@RequestParam(required = false)int age);
@PostMapping("oneObject")
public String oneObject(@RequestBody User user);
}
@GetMapping("paramTest")
public String paramTest(){
userProviderFeign.paramUrl("张三",20);
userProviderFeign.getParam("李四");
userProviderFeign.twoParam("小红",18);
User user = User.builder()
.name("小冰")
.age(18)
.time(new Date()).build();
userProviderFeign.oneObject(user);
return "provider";
}
Feign传递时间
@GetMapping("testTime")
public String testTime(@RequestParam Date date){
return date +"";
}
@GetMapping("time")
public String time(){
Date date =new Date();
System.out.println(date);
String s = userProviderFeign.testTime(date);
return s;
}
Feign日志处理
Feign提供了日志打印功能,我们在项目中可以通过配置来调整日志级别,从而了解Feign中http请求的细节 ,也就是说feign提供的日志功能可以对接口的调用情况进行监控和输出。
日志级别:
NONE: 默认的,不显示任何日志
BASIC:仅记录请求方法、URL、响应状态码以及执行时间
HEADERS:除了BASIC中定义的信息以外,还有请求和响应的头信息
FULL: 除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据
public Logger.Level level(){
return Logger.Level.FULL;
}
logging:
level:
com.example.feign.UserProviderFeign : debug