在前面我们了解了Ribbon,但随着互联网技术的成熟,我们程序员不仅仅追求实现功能,开始对微服务中通信调用效率与便捷开始了探索,OpenFeign开始走向我们大众的视野。
一、为什么要使用OpenFeign?
尽管 Ribbon 和 Eureka 提供了负载均衡和服务发现的核心功能,但当我们通过RestTemplate调用其它服务时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下
,OpenFeign 提供了更高级的抽象和便利性,使得微服务之间的通信更加简单和优雅。它提供了声明性 API 定义、集成负载均衡和服务发现、错误处理和容错机制等功能,使得开发人员可以更专注于业务逻辑,减少了大量的样板代码和配置。
OpenFeign的优点在于:
声明性 API 定义: OpenFeign 提供了基于注解的方式来定义和描述服务间的 API 接口,使得开发人员可以以接口的形式定义微服务之间的交互,而无需手动编写 HTTP 请求和解析响应的代码。这使得代码更加清晰、简洁和可维护。
集成负载均衡和服务发现: OpenFeign 默认集成了 Ribbon 和 Eureka,使得在调用服务时可以自动进行负载均衡和服务发现。通过 OpenFeign,你可以直接使用服务名来调用其他微服务,而不需要关心具体的服务实例。
错误处理和容错机制: OpenFeign 提供了丰富的错误处理和容错机制。它可以处理不同的 HTTP 状态码、重试策略、断路器等,以提高微服务之间的可靠性和容错性。
集成性和开箱即用: OpenFeign 可以轻松地集成到 Spring Cloud 中,并与其他组件(如 Spring Boot、Ribbon、Eureka)无缝协同工作。它提供了一系列的自动配置选项,使得使用 OpenFeign 变得非常简单,只需在代码中添加相应的注解即可开始使用。
可扩展性: OpenFeign 具有良好的扩展性,可以通过自定义编码器、解码器、拦截器等来满足特定的需求。你可以根据业务需求自定义和扩展 OpenFeign 的功能。
二、什么是OpenFeign?
提到OpenFeign,就不得不提到另一个HTTP服务客户端,Feign。Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端,Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。
但是Feign是在2019就已经不再更新了,通过maven网站就可以看出来,随之取代的是OpenFeign,从名字上就可以知道,他是Feign的升级版。
OpenFeign是Spring Cloud 在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
三、如何使用OpenFeign?
1.OpenFeign的工作原理?
- SpringBoot工程启动,通过@EnableFeignClients扫描所有@FeignClient对应的接口
- Feign框架的FeignClientFacotoryBean 为接口产生Proxy实例,并通过Spring容器注入到调用者
- 调用者通过OpenFeign接口调用某个方法,由Proxy实例转发至FeignFrameWork框架的InvocationHandler 对象
- 该 Handler 完成后续的 HTTP 转换, 发送, 接收, 翻译HTTP响应等工作
具体流程见下图。
2.如何配置OpenFeignClient?
2.1 导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--2.导入Feign的包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency
2.2 启动类修改
@SpringBootApplication
// 表名此服务是Eure客户端,开启Eureka客户端功能,不加此注解默认也开启客户端功能
@EnableFeignClients
public class PayServerApplication
{
public static void main( String[] args )
{
SpringApplication.run(PayServerApplication.class,args);
}
}
启动类增加@EnableFeignClients标签 , 其value属性可以指定Feign的客户端接口的包,当然也可以省略value属性,@EnableFeignClients开启Feign支持,告诉框架扫描所有使用注解@FeignClient定义的feign客户端,并把feign客户端注册到IOC容器中。
2.3 yml进行配置
server:
port: 10040 # user服务端口号
eureka:
client:
serviceUrl: # Eureka客户端配置,指向注册中心地址
defaultZone: http://localhost:10010/eureka/
instance: # 打开IP注册
instance-id: ${spring.application.name}:${server.port} # 设置实例名称
prefer-ip-address: true # 开启IP注册
# 指定服务名称,此服务下的集群所有服务都叫此服务名
spring:
application:
name: pay-server
#开启日志
logging:
level:
cn.hc: debug
2.4 编写FeignClients客户端接口
import cn.hc.domain.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
//@FeignClient("user-server")使用FeignClient调用服务名为user-server用户服务
@FeignClient(value = "user-server" )
public interface UserFeignClient {
//调用用户服务的接口
//最终完整调用用户服务的Url:"http://user-server/user/" + id
@GetMapping("/user/{id}")
User getUser(@PathVariable("id") Long id);
}
其中@FeignClient("user-server")使用FeignClient调用服务名为user-server用户服务
Feign可以根据@FeignClient("user-server")找到用户服务,根据方法上的 @RequestMapping(value = "/user/{id}",method = RequestMethod.GET)找到目标服务的controller的方法 ,我们在使用Feign接口时传入的参数就会作为目标服务controller方法的参数,而返回值就是目标服务controller方法的返回值。
即:服务名要一致 , url路径要一致 , 参数要一致 , 返回值类型要一致。
2.5 使用接口进行调用
@RestController
public class PayController {
@Autowired
private UserFeignClient userFeignClient;
@RequestMapping("/pay/{id}")
public User getById(@PathVariable("id") Long id) {
return userFeignClient.getUser(id);
}
}
2.6 测试
通过浏览器访问pay-server的controller:http://localhost:1040/pay/1,多次请求发现依然默认使用了轮询
3.OpenFeign的日志调试
3.1 配置Feign日志打印内容
有的时候我们需要看到Feign的调用过程中的参数及相应,我们可以对Feign的日志进行配置,Feign支持如下几种日志模式来决定日志记录内容多少:
NONE,不记录(DEFAULT)。
BASIC,仅记录请求方法和URL以及响应状态代码和执行时间。
HEADERS,记录基本信息以及请求和响应标头。
FULL,记录请求和响应的标题,正文和元数据。
3.2 配置Feign日志的步骤
配置类修改
#开启日志
logging:
level:
cn.hc: debug
cn.hc是你所要扫描的包名。
创建配置类
@Configuration
public class FeignConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL; //打印Feign的所有日志
}
}