Spring Cloud

Feign声明式HTTP客户端

2019-08-20  本文已影响0人  初心myp

1. Feign的定义

Feign是Netflix开源的声明式客户端

解析:声明式HTTP客户端,我们只需要声明一个接口,Feign就会通过我们定义的接口,自动构造请求的目标地址,并完成发送请求
GitHub地址:https://github.com/openfeign/feign

2. 整合Feign

2.1 加依赖
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.0.2.RELEASE</version>
        </dependency>
2.2 加注解

在启动类上面加@EnableFeignClients注解

3. 实际应用

首先我们之前服务之间的调用使用的是RestTemplate,使用RestTemplate会存在一些问题。所以我们考虑使用Feign代替RestTemplate,接下来我们就实现一下:
我们是内容中心调用用户中心的服务,所以我们在内容中心添加一个用户中心服务的接口类,代码如下:

package com.chuxin.contentcenter.feignclient;

import com.chuxin.contentcenter.dao.dto.UserDTO;
import feign.Param;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @FileName: UserFeignClients
 * @Description: 用户中心的Feign远程调用接口类
 * @author: <a href="mailto: muyuanpei@camelotchina.com">myp</a>
 * @create: 2019-08-16 14:17
 * @Copyright: (c) 初心科技有限公司(待创)
 */
//name值为用户服务的名称
@FeignClient(name = "user-center")
public interface UserCenterFeignClient {

    @GetMapping("/users?id={id}")
    UserDTO findById(@PathVariable("id") Integer id);

}

然后我们在业务代码里面就可以通过该接口类直接调用就可以了。

@Autowired
private UserCenterFeignClient userCenterFeignClient;
//业务代码里这样直接调用就ok了
UserDTO userDTO = userCenterFeignClient.findById(userId);

通过使用FeignClient的方式相对于使用RestTemplate方式,可以解决以下问题:

  1. 编码的可读性差
  2. 复杂的url难以维护
  3. 难以响应需求的变化,变化很没有幸福感
  4. 编程体验不统一

4. Feign的组成

Feign的源码里面使用了大量的设计模式,比如建造者模式,代理模式等等。

image.png
1. Feign.Builder:Feign的入口,每一个FeignClient都是由他构建的
2. Client:指定Feign的底层用什么去请求。Feign.Client.Default使用的是用urlconnection去请求的,urlconnection没有连接池,也没有资源管理的概念,性能不是特别好;LoadBalancerFeignClient这个类用到了代理模式,代理了Client接口,这意味着你可以传一个你喜欢的Client过来使用,默认就是Client.Default
3.Contract:注解支持,Feign支持使用SpringMVC的注解,是由SpringMVCContract实现的

5. Feign的细粒度配置

和ribbon一样,两种方式。代码方式和属性方式
以配置Feign的日志打印级别入手学习(默认Feign是不打印任何日志的),spring打印日志级别是在配置文件中配置如下代码就可以了,但是Feign这样配置可不行

logging:
  level:
    com.chuxin: debug

Feign的四种自定义日志级别

级别 打印内容 适用场景
NONE(默认值) 不记录任何日志
BASIC 仅记录请求方式、url、响应状态码以及执行时间 生产环境
HEADERS 记录BASIC级别基础上,记录请求和响应的hearder
FULL 记录请求和响应的header、body和元数据(全部信息) 开发环境

5.1 代码方式

我们举例配置FULL级别的日志打印
首先我们在上面的基础上改一下UserCenterFeignClient.java这个类,在上面的注解添加configuration = xxx.class即可,修改后代码如下:

package com.chuxin.contentcenter.feignclient;

import com.chuxin.contentcenter.config.UserCenterFeignConfig;
import com.chuxin.contentcenter.dao.dto.UserDTO;
import feign.Param;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

/**
 * @FileName: UserFeignClients
 * @Description: 用户中心的Feign远程调用接口类
 * @author: <a href="mailto: muyuanpei@camelotchina.com">myp</a>
 * @create: 2019-08-16 14:17
 * @Copyright: (c) 初心科技有限公司(待创)
 */
//name值为用户服务的名称
@FeignClient(name = "user-center" ,configuration = UserCenterFeignConfig.class)
public interface UserCenterFeignClient {

    @GetMapping("/users?id={id}")
    UserDTO findById(@PathVariable("id") Integer id);

}

UserCenterFeignConfig类如下:

package com.chuxin.contentcenter.config;

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

/**
 * @FileName: UserCenterFeignConfig
 * @Description: 配置Feign日志打印级别的配置类。也可以添加其他的配置
 * @author: <a href="mailto: muyuanpei@camelotchina.com">myp</a>
 * @create: 2019-08-16 15:13
 * @Copyright: (c) 初心科技有限公司(待创)
 */
//@Configuration
public class UserCenterFeignConfig {

    @Bean
    public Logger.Level level(){
        //配置Feign打印所有请求的细节
        return Logger.Level.FULL;
    }
}
/**
 * 注意:
 * @Configuration这个注解如果加上就需要将这个类放到启动类扫描不到的包下面,如果不加,这个类就放在启动类可以扫描的包下面
 * 如果@Configuration注解使用错误,就会存在父子上下文重复问题
 * */

最后在配置文件中添加,如下配置:

# 配置日志打印级别
logging:
  level:
    # 接口全路径:debug级别日志
    com.chuxin.contentcenter.feifnclient.UserCenterFeignClient: debug

这样就配置完成了,在进行调用就会打印Feign的日志了。

5.2 属性方式

这个就简单多了,在文章上面第三点的基础上,在配置文件中添加一行配置就可以搞定了
配置代码如下:

feign:
  client:
    config:
      # 想要调用的微服务名称
      user-center:
        loggerLevel: full

这样就可以了,完成了和代码配置一样的效果

6. Feign的全局配置

6.1 代码方式

在启动类上面添加注解@EnableFeignClients(defaultConfiguration = UserCenterFeignConfig.class)
然后添加一个全局的配置类就ok了,配置类放在启动类可以扫描的包结构下,配置类代码如下:

package com.chuxin.contentcenter.config;

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

/**
 * @FileName: UserCenterFeignConfig
 * @Description: 配置Feign日志打印级别的配置类。也可以添加其他的配置
 * @author: <a href="mailto: muyuanpei@camelotchina.com">myp</a>
 * @create: 2019-08-16 15:13
 * @Copyright: (c) 初心科技有限公司(待创)
 */
public class GlobalFeignConfig {

    @Bean
    public Logger.Level level(){
        //配置Feign打印所有请求的细节
        return Logger.Level.FULL;
    }

}
/**
 * 注意:
 * 这个注解如果加上就需要将这个类放到启动类扫描不到的包下面,如果不加,这个类就放在启动类可以扫描的包下面
 * 如果@Configuration注解使用错误,就会存在父子上下文重复问题
 * */

完成!!!

6.2 属性方式

在配置文件中,添加如下配置即可:

feign:
  client:
    config:
      # 将想要调用的微服务名称换成default就可以实现属性方式的全局配置了
      default:
        loggerLevel: full

7. Feign支持的配置项

使用代码方式和使用属性方式支持的配置项稍有不同

7.1 使用代码方式支持的配置项
配置项 作用
Logger.Level 指定日志级别
Retryer 指定重试策略
ErrorDecoder 指定错误解码器
Request.Options 超时时间
Collection<RequestInterceptor> 拦截器
SetterFactory 用于设置Hystrix的配置属性,Feign整合Hystrix才会用
7.2 使用属性方式支持的配置项
feign:
  client:
    config:
      # 想要调用的微服务名称
      default:
        loggerLevel: full # 日志级别四种: NONE(默认值)、BASIC、HEADERS、FULL
        connectTimeout: 5000 # 连接超时时间
        readTimeout: 5000 # 读取超时时间
        errorDecoder: com.example.SimpleErrorDecoder # 错误解码器
        retryer: com.example.SimpleRetryer # 重试策略
        requestInterceptor: com.example.SimpleRequestInterceptor # 拦截器
        # 是否对404错误码解码
        # 处理逻辑详情见feign.SynchronousMethodHandler#executeAndDecode
        decode404: false
        encoder: com.example.SimpleEncoder # 编码器
        decoder: com.example.SimpleDecoder # 解码器
        contract: com.example.SimpleContract # 契约

8. 对比

image.png
image.png

优先级由低到高:全局代码 < 全局属性 < 细粒度代码 < 细粒度属性

9. 配置的最佳实践

上一篇下一篇

猜你喜欢

热点阅读