微服务调用组件 Feign

前言

Java 项目中如何实现接口调用

1、Httpclinet

HtpClient 是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持Htp协议的客户端编程工具包,并且它支持HTTP协议最新版本和建议。HtpClient相比传统JDK自带的URLConnection,提升
了易用性和灵活性,使客户端发送HTTP请求变得容易,提高了开发的效率。

2、OkHttp

一个处理网络请求的开源项目, 安卓端最火的轻量级框架,由Square公司贡献,于替代HttpUrlConnection 和Apache HttpClient。OkHttp 拥有简洁的 API、高效的性能,技持多种协议(HTTP/2SPDY)3、HttpURLConnection

HttpURLConnection是Java的标准类,它继承自URLConnection,可用于向指定网站发送GET请求、POST 请求。HttpURLConnection 使用比较复杂,不像HttpClient那样容易使用。

4、RestTemplate WebClinet
RestTemplate是Spring提供的用于访问Rest服务的客F端,RestTemplate 提供了多种便捷访问远程HTTP服务的方法,能够大大提高客户端的编写效率。上面介绍的是最常见的几种调用接口的方法,我们下面要介绍的方法比上面的更简单、方便,它就是Feign。

一、什么是 Feign

Feign是Netix开发的声明式、模板化的HTTP客户端,其灵感来自Retrofit、 JAXRS-2 .0以及WebSocket。Feign可帮助我们更加便捷、优雅地调用HTTP API。Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。

SpringCloud OpenFeign 对 Feign 进行了增强,对其支持 Spring Mvc 注解,另外还整合了 Ribbon 和 Nacos,从而使得 Feign 的使用更加方便

1.1、优势

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

二、Spring Cloud Alibaba 快读整合 OpenFeign

2.1、引入依赖

    <dependencies>
        <!--1.添加 openfeign 依赖,需要引入 spring-cloud 的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

2、添加 feign 接口和方法

/**
 * name 指定调用 rest 接口所对应的服务名
 * path 指定调用 rest 接口所在的 StockController 指定的 @RequestMapping
 */
@FeignClient(name = "stock-server",path = "/stock")
public interface StockFeignService {
    // 声明需要调用的 rest 接口对应的方法
    @RequestMapping("/reduce")
    String reduce();
}

对比实际的接口代码

微服务调用组件 Feign

2.3、发起调用,像调用本地方法一样调用远程服务

@RestController
@RequestMapping(value = {"/order"})
public class OrderController {

    @Autowired
    private StockFeignService stockFeignService;

    @RequestMapping("/add")
    public String add() {
        System.out.println("下单成功!");
        String message = stockFeignService.reduce();
        return "Hello Feign " + message;
    }
}

2.4、调用端在启动类加上添加@EnableFeignClients注解

@SpringBootApplication
@EnableFeignClients
public class OrderServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServerApplication.class,args);
    }
}

目录结构如下

微服务调用组件 Feign

启动 stock-serverorderopefeignserver服务,访问http://localhost:8040/order/add

三、Spring Cloud OpenFeign 的自定义配置及使用

Feign 提供了很多扩展机制,让用户可以更加灵活使用。

3.1、日志配置

有时候我们遇到 Bug,比如接口调用失败、参数没收到等问题,或者想看看调用性能,就需要配置 Feign 的日志了,以此让 Feign 把请求信息输出来。

项目结构如下

微服务调用组件 Feign

3.1.1、自定义一个配置类,指定日志级别

/**
 * 全局配置:当使用 @Configuration 会将配置作用所有的服务提供方
 * 局部配置:如果只想针对某一个服务进行配置,不用 @Configuration
 */
@Configuration
public class FeignConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

通过源码可以看到日志等级有 4 种,分别是

  • NONE(性能最佳,适用于生产):不记录任何日志(默认值)
  • BASIC(适用于生产环境追踪问题):仅记录请求方法、URL、响应状态以及执行时间。
  • HEADERS:记录 BASIC 级别基础上,记录请求和响应的 header
  • FULL(比较适用于开发以及测试环境定位问题):记录请求和响应时间的 header、body和元数据

3.1.2、局部配置,让调用的微服务生效,在@FeignClient注解中指定使用的配置

@FeignClient(name = "product-server",path = "/product",configuration = FeignClient.class)
public interface ProductFeignService {
    @RequestMapping("/{id}")
    String get(@PathVariable("id") Integer id);
}

3.1.3、在 yml 配置文件中指定 Client 的日志级别才能正常输出日志,格式是”logging.level.feign接口包路径=debug”

# springboot 默认的日志级别是 info,feign 的 debug 日志级别不会输出
logging:
  level:
    # 指定包的日志级别
    com.hudu.order.feign: debug

详细日志信息

微服务调用组件 Feign

补充:局部配置可以在 yml 中配置

对应属性配置类:org.springframework.cloud.openfeign.FeignClientProperties

# feign 日志局部配置
feign:
  client:
    config:
      # 对应微服务
      product-server:
        loggerLevel: FULL

3.2、契约配置

Spring Cloud 在 Feign 的基础上做了扩展,使用 Spring MVC 的注解来完成 Feign 的功能。原生的 Feign 是不支持 Spring MVC 注解的,如果你想在 Spring Cloud 中使用原生的注解方式来定义客户端也是可以的,通过配置契约来改变这个配置,Spring Cloud 中默认的是 SpringMvcContract.
Spring Cloud 早期版本就是使用的原生的 Feign,随着 netflix 的停更,替换成了 Open feign

一般使用场景为,SpringCloud 版本升级,保留原生的注解。

3.2.1、修改契约配置,支持 Feign 原生的注解

/**
* 修改契约配置,支持 Feign 原生的注解
*/
@Bean
public Contract feignContract() {
    return new Contract.Default();
}

注意:修改契约配置后,OrderFeignService 不再支持 springmvc注解,需要使用 Feign 原生的注解

3.2.2、OrderFeignService 中配置使用 Feign 原生的注解

@FeignClient(name = "product-server",path = "/product")
public interface ProductFeignService {
    @RequestLine("GET /{userId}")
    String get(@Param("userId") Integer userId);
}

3.2.3、补充,也可以通过 yml 配置契约

# feign 日志局部配置
feign:
  client:
    config:
      # 对应微服务
      product-server:
        contract: feign.Contract.Default # 指定 Feign 原生注解契约配置

3.3、超时时间配置

通过 Options 可以配置连接超时时间和读取超时时间,Options 的第一个参数是连接的超时时间 (ms) ,默认值是2s;第二个是请求处理的超时时间(ms) , 默认值是5s.

3.3.1、全局配置

/**
* 超时时间配置
*/
public Request.Options options() {
    return new Request.Options(5000,10000);
}

3.3.2、yml 中配置

feign:
  client:
    config:
      # 对应微服务
      product-server:
        # 连接超时时间,默认 2 s
        connectionTimeout: 5000
        # 请求处理超时时间,默认 5 s
        readTimeout: 10000

补充说明:Feign 的底层用的是 Ribbon,但超时时间以 Feign 配置为准。

微服务调用组件 Feign

3.4、自定义拦截器实现认证逻辑

public class CustomFeignInterceptor implements RequestInterceptor {
    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void apply(RequestTemplate requestTemplate) {
        // 业务逻辑
        String access_token = UUID.randomUUID().toString();
        requestTemplate.header("Authorization", access_token);
        // query String 方式传参
        requestTemplate.query("id", "111");
        // 占位符方式,修改掉请求的id
        requestTemplate.uri("/9");
        logger.info("feign 拦截器!");
    }
}


// 全局配置
@Configuration
public class FeignConfig {
  @Bean
  public Logger.Level feignLoggerLevel() {
  return Logger.Level.FULL;
  }
  @Bean
  public CustomFeignInterceptor customFeignInterceptor() {
  return new CustomFeignInterceptor();
  }
}

补充:可以在配置文件中配置

feign:
  client:
    config:
      # 对应微服务
      product-server:
        # 配置拦截器
        requestInterceptors[0]:
          com.hudu.order.interceptor.feign.CustomFeignInterceptor

product-server 端可以通过 @RequestHeader 获取请求参数,建议在 filter,Interceptor 中处理。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!