SpringCloud 之OpenFeign服务消费者

Feign简介

官网地址:https://github.com/OpenFeign/feign

Feign是一个声明式的Web服务客户端,让编写Web服务客户端变得非常容易,只需 创建一个接口并在接口上添加注解即可。
在这里插入图片描述
Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果。

  • Feign 采用的是基于接口的注解
  • Feign 整合了ribbon,具有负载均衡的能力
  • 整合了Hystrix,具有熔断的能力

OpenFeign简介

Spring Cloud提供的Feign增强版,使得Feign支持Spring MVC的注解,开发更容易了。

OpenFeign快速入门

创建一个model工程作为服务消费者,即eureka-feign-client
导入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在启动类中添加 @EnableFeignClients 注解开启Feign的功能。

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
// 开启Feign的功能
@EnableFeignClients
public class EurekaFeignClientApplication {

	public static void main(String[] args) {
		SpringApplication.run(EurekaFeignClientApplication.class, args);
	}
}

配置文件appication.yml

server:
  port: 8083

spring:
  application:
    name: eureka-feign-client

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8100/eureka/

定义一个Feign接口,在接口上加@FeignClient注解来声明一个 Feign Client,
其中value为远程调用其他服务的服务名。

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

// 申明这是一个Feign客户端,并且指明服务id
@FeignClient(value = "eureka-client")
public interface FeignClientInter {

    // 这里定义了类似于SpringMVC用法的方法,就可以进行RESTful方式的调用了
    @GetMapping(value = "/hello")
    String sayHelloFromClient();
}

通过上面定义的Feign客户端来消费服务。

import com.yq.feign.service.FeignClientInter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @Autowired(required = false)
    FeignClientInter feignClientInter;

    @GetMapping("/feign")
    public String demo() {
        return feignClientInter.sayHelloFromClient();
    }
}

启动测试
在浏览器上多次访问http://127.0.0.1:8083/feign,浏览器交替显示,说明集成了Ribbon负载均衡。
在这里插入图片描述
在这里插入图片描述

OpenFeign超时控制

OpenFeign默认等待1秒钟。超过后报错。
在这里插入图片描述
超时配置:

# 设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
  # 指的是建立连接所用的时间,适用于网络状态正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
  # 指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

OpenFeign日志打印功能

在这里插入图片描述
日志级别:
在这里插入图片描述
配置日志Bean:

import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
        // 请求和响应的头信息,请求和响应的正文及元数据
        return Logger.Level.FULL;
    }
}

YML文件里需要开启日志的Feign客户端:

logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.demo.service.PaymentFeignService: debug

后台查看日志:
在这里插入图片描述

Feign的工作原理

Feign 是一个伪 Java Http 客户端 , Feign 不做任何的请求处理。 Feign 通过处理注解生成 Request 模板,从而简化了 Http API 的开发。
开发人员可以使用注解的方式定制 Request API 模板。在发送 HttpRequest 请求之前 , Feign 通过处理注解的方式替换掉 Request 模板中的参数,生成真正的 Request ,并交给 Java Http 客户端去处理 。利用这种方式,开发者只需要关注 Feign 注解模板的开发 ,而不用关注 Http 请求本身,简化了 Http 请求的过程 ,使得 Http 请求变得简单和容易理解。

  • Feign 通过包扫描注入 FeignClient 的 Bean ,该源码在 FeignClientsRegistrar 类中 。首先在程序启动时,会检查是否有@EnableFeignClients 注解,如果有该注解,则开启包扫描,扫描被@FeignClient 注解的接口 。
    在这里插入图片描述

  • 当程序的启动类上有@EnableFeignClients注解。在程序启动后,程序会通过包扫描将有@FeignClient 注解修饰的接口得到一个BeanDefinition ,并将BeanDefinition 注入 IoC 容器中。org.springframework.cloud.openfeign.FeignClientsRegistrar#registerFeignClients

  • 通过 JDK 的代理,当调用 FeignClient 接口里面的方法时,该
    方法会被拦截,源码在 ReflectiveFeign 类。
    在这里插入图片描述

  • SynchronousMethodHandler 类进行拦截处理,会根据参数生成RequestTemplate 的Http请求模板对象,然后调用 executeAndDecode()方法,该方法通过 RequestTemplate 生成 Request请求对象,然后用 HttpClient 获取 Response ,即通过 HttpClient 进行 Http 请求来获取响应。
    在这里插入图片描述
    最终通过Client的实现类LoadBalancerFeignClient ,即负载均衡客户端,来实现负载均衡请求调用服务的。

在Feign中使用HttpClient和OkHttp

首先查看 FeignRibbonClient 的自动配置类 FeignRibbonClientAutoConfiguration ,@Import 自动注入三个请求框架,从名字上可以看出默认使用最后一个Client。

HttpClientFeignLoadBalancedConfiguration
OkHttpFeignLoadBalancedConfiguration
DefaultFeignLoadBalancedConfiguration

在这里插入图片描述
查看DefaultFeignLoadBalancedConfiguration源码,通过new Client.Default()来创建Client的。
在这里插入图片描述
实现类是 Client.Default,,Client.Default 是由 HttpURLConnnection 来实现网络请求的。
在这里插入图片描述
继续分析@Import导入的类,FeignClient 还支持 HttpClient 和 OkhHttp 来进行网络请求,那么 Feign 中如何选择网络请求框架呢?
下面继续查看HttpClientFeignLoadBalancedConfigurationOkHttpFeignLoadBalancedConfiguration源码。
在这里插入图片描述
在这里插入图片描述
从代码@ConditionalOnClass(ApacheHttpClient.class)@ConditionalOnClass(OkHttpClient.class)注解可知道,只需要在 POM 文件加上HttpClient或者OkHttpClient 的 Classpath 即可 。
另外需要在配置文件 application.yml 中配置feign.httpclient.enabled或者feign.okhttp.enabled为 true,从 HttpClientFeignLoadBalancedConfiguration类上的@ConditionalOnProperty注解可知,这个配置可以不写,因为在默认的情况下就为true,如果使用OkHttp,必须配置feign.okhttp.enabled,因为OkHttpFeignLoadBalancedConfiguration类上的@ConditionalOnProperty注解未设置为true。

POM 文件加上 feign-httpclient 的依赖, Feign 就会采用 HttpClient 作为网络请求框架。

<dependency>
    <groupId>com.netflix.feign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>RELEASE</version>
</dependency>

POM 文件加上 feign-okhttp 的依赖, Feign 就会采用 OkHttp 作为网络请求框架。

<dependency>
    <groupId>com.netflix.feign</groupId>
    <artifactId>feign-httpclient</artifactId>
    <version>RELEASE</version>
</dependency>

如果容器中三个Client都存在,Feign会默认根据@Import注入类的顺序来选择Client。在LoadBalancerFeignClient类中可以看出使用了哪个Client。
在这里插入图片描述

Feign调用链

在这里插入图片描述

OpenFeign与Ribbon区别

Ribbon侧重于做服务调用时的负载均衡,而OpenFeign侧重于面向接口进行服务调用。

在只引入Ribbon依赖的时候,可以使用restTemplate来进行服务调用,大概流程如下:
在这里插入图片描述

OpenFeign相比Ribbon在代码实现上是在客户端多了一层接口,之前用Ribbon的时候客户端只有Controller层,通过RestTemplate请求服务端的Controller层。

Openfeign需要在客户端创建一个service层,并创建一个service接口(要用到@FeignClient注解),其方法和服务端的Controller里的方法相对应,之后客户端的Controller调这个接口就行了。

OpenFeign的引入直接砍掉了RestTemplate,客户端Controller在调用服务端时不需要再关注请求的方式、地址以及是forObject还是forEntity,完全面向接口调用,层次结构更加明了,而且OpenFeign自身集成Ribbon,所以默认开启轮询的负载均衡。而且还可以和Hystrix相结合,写一个类实现service接口,其中实现的方法的方法体便是降级或熔断的fallback方法(需要在接口中指定该实现类)。这样结构更清晰,耦合也更低。

总结如下

1、通过 @EnableFeignCleints 注解启动 Feign Starter 组件。
2、Feign Starter 在项目启动过程中注册全局配置,扫描包下所有的 @FeignClient 接口类,并进行注册 IOC 容器。
3、@FeignClient 接口类被注入时,通过 FactoryBean#getObject 返回动态代理类。
4、接口被调用时被动态代理类逻辑拦截,将 @FeignClient 请求信息通过编码器生成 Request(没有带上Header头)。
5、交由 Ribbon 进行负载均衡(默认轮询的方式),挑选出一个健康的 Server 实例。
6、继而通过 Client 携带 Request 调用远端服务返回请求响应。
7、通过解码器生成 Response 返回客户端,将信息流解析成为接口返回数据。

掌握 OpenFeign 核心原理

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值