微服务调用组件Feign

  • Post author:
  • Post category:其他


一、什么是Feign

1、Feign是Netflix开发的声明式、模板化的HTTP的客户端,它能帮助我们更加便捷、优雅地调用HTTP API,它也支持多种注解(例如Feign自带的注解)。

2、Spring Cloud Openfeign对Feign进行了增强,使其支持Spring MVC 注解,另外整合了Ribbon和Eureka,从而使得Feign的使用更加便捷。

二、Feign的优势

Feign可以做到使用HTTP请求远程服务时就像调用本地方法一样的体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。它像Dubbo一样,consumer直接调用接口方法调用provider,而不需要通过常规的Http Client构造请求再解析返回数据。它解决了让开发者调用远程接口就跟调用本地方法一样,无需关注与远程的交互细节,更无需关注分布式环境开发。

三、Feign的设计原理

1、基于面向接口的动态代理方式实现生产实现类;

2、根据接口类的注解声明规则,解析出底层MethodHandler;

3、基于RequestBean动态生成Request;

4、Encoder将Bean包装成请求;

5、拦截i去负责对请求和返回进行装饰处理;

6、日志记录;

7、基于重试器发送http请求,可基于不同的http框架处理。

四、Feign与Ribbon

1、微服务中为什么使用Feign而不使用Ribbon

①:如果使用Ribbon需要直接加上RestTemplate去调用,调用端需要拼接大量url,这种很难维护

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
       return new RestTemplate();
}

//调用方式
String url = "http://mall-order/order/findOrderById/"+id;
R rest = restTemplate.getForObject(url,R.class);

②:Feign是在客户端定义一个接口,接口里面有需要调用的方法,通过依赖注入获取到代理对象,而后代理对象调用方法,实现很简洁方便。

@FeignClient(value="mall-order",path="/order")
public interface OrderFeignService {
    
    @RequestMapping("findOrderById/{userId}")
    public R findOrderById(@PathVariable("userId") Integer userId);
}

@Autowired
OrderFeignService orderFeignService;
//Feign调用
R result = OrderFeignService.findOrderById(userId);

2、Spring Cloud整合Feign

①:引入依赖,编写调用接口+@FeignClient注解,调用端在启动器类上添加@EnableFeignClients注解,发起调用(像调用本地方式一样调用远程服务)

注:Feign的继承特性可以让服务的接口定义单独抽出来,作为公共的依赖,以方便使用。

五、Feign的日志

1、Feign的日志级别

有时候,我们遇到问题需要查看参数等信息,就需要配置Feign的日志。

①、NONE【性能最佳,适用于生产】:不记录任何日志(默认值)

②、BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间

③、HEADERS:记录BASIC级别的基础上,记录请求和响应的header

④、FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据。

2、Feign的局部日志配置

如果生产中有多个服务,只需要某个微服务打印下日志,这时可以在@Feign注解中增加个configuration来指定Feign且Feign上的注解@Configuration需要去掉(因为如果在FeignConfig上加了@Configuration注解,启动的时候就会被扫描到,要想局部打印日志就需要避免全局配置),不过不建议这样去配置,很容易搞混成全局配置,可以在yam文件中加配置来实现。

@FeignClient(value="mall-order",path="/order",configuration="FeignConfig.class")
public interface OrderFeignService {
    
    @RequestMapping("findOrderById/{userId}")
    public R findOrderById(@PathVariable("userId") Integer userId);
}

局部配置可以在yml中配置

feign: 
    client:
        config:
            mall-order:  #对应微服务
                loggerLevel: Full

3、通过拦截器实现认证

通过我们调用的接口都是由权限控制的,很多时候可能认证的值都是通过参数去传递的,还有就是通过请求头去传递认证信息,比如Basic认证方式

注:这里需要自定义拦截器来实现认证逻辑,feign.RequestInterceptor每次feign发起http调用之前,会去执行拦截器中的逻辑,使用场景:①统一添加header信息,②:对body中的信息做修改或替换

//Feign中我们可以直接配置Basic认证
@Configuration 
public class FeignConfig {
    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor("user","password");
    }
}



版权声明:本文为eg1107原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。