由浅入深拿下OpenFeign

1、OpenFeign是什么?

OpenFeign是一个Web声明式的Http客户端调用工具。是Spring Cloud官方对Feign的增强,它支持spring mvc的注解。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样。

2、环境准备

本文基于Springboot 2.6.8,服务注册中心使用的Nacos 版本用的最新的2021.0.1.0。看一下相关的Pom依赖

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
    </dependency>
<!-- spring-cloud-starter-alibaba-nacos-config -->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2021.0.1.0</version>
    </dependency>
    
    <!-- spring-cloud-starter-alibaba-nacos-discovery -->
    <dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2021.0.1.0</version>
    <!--不使用Ribbon 进行客户端负载均衡-->
    <exclusions>
    <exclusion>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>3.1.1</version>
    </dependency>
    
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
    <version>3.1.1</version>
    </dependency>
    
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
    <version>3.0.4</version>
        </dependency>

这里简单讲解一下,不是本文重点:

  1. 由于Ribbon停止维护,所以新版的SpringCloud已经不用它了,所以需要引入spring-cloud-starter-loadbalancer,并且在nacos依赖中排除掉ribbon。
  2. Springboot2.4+需要引入spring-cloud-starter-bootstrap

3、服务提供者

bootstrap.yml

server:
  port: 8081
spring:
  cloud:
    nacos:
      discovery:
        server-addr: ip
        service: provider

新建接口

@RestController
@RequestMapping("/provider")
public class ProviderController {

    @PostMapping("/getOrder")
    Order getOrder(@RequestBody OrderRequest request){
        System.out.println(request.getId());
        System.out.println(request.getClassify());
        return Order.builder().code("JSON数据").build();
    }

    @GetMapping("/findOrder/{id}")
    Order findOrder(@PathVariable("id") Integer id){
     return Order.builder().id(id).count(50).code("URL携带参数").build();
    }

    @GetMapping("/findOrder")
    Order findOrder(@SpringQueryMap OrderRequest request){
    return Order.builder().code("POJO表单参数").build();
    }

    @GetMapping("/findOrder2")
    Order queryOrder(@RequestParam("id") Integer id,
                     @RequestParam("code") String code){
        System.out.println(id);
        System.out.println(code);
    return Order.builder().code("普通表单参数").build();
    }

订单实体类

@Data
@Builder
public class Order {

    private Integer id;

    private String code;

    private Integer userId;

    private Integer count;

    private BigDecimal money;

}

查询参数类

@Data
public class OrderRequest {

    private Integer id;

    private String name;

    private String classify;

    private Integer number;
}

4、服务消费者

bootstrap.yml

server:
  port: 8082
spring:
  cloud:
    nacos:
      discovery:
        server-addr: ip
        service: consumer
  • @EnableFeignClients 启用Feign客户端
  • @FeignClient 标记Feign客户端

在主程序的上加上注解@EnableFeignClients

新建一个接口 name填服务提供者注册到nacos的服务名

@FeignClient(name = "provider",path = "provider")
public interface FeignProviderService {
        @PostMapping("/getOrder")
        Order getOrder(@RequestBody OrderRequest request);

        @GetMapping("/findOrder/{id}")
        Order findOrder(@PathVariable("id") Integer id);

        @GetMapping("/findOrder")
        Order findOrder(@SpringQueryMap OrderRequest request);

        @GetMapping("/findOrder2")
        Order queryOrder(@RequestParam("id") Integer id,
                         @RequestParam("code") String code);
}

这样就可以在消费者的Service中直接注入使用

@Service("consumerService")
public class ConsumerServiceImpl implements ConsumerService {

    @Autowired
    FeignProviderService feignProviderService;

    @Override
    public Order dealOne() {
        OrderRequest orderRequest = new OrderRequest();
        orderRequest.setId(1);
        orderRequest.setClassify("777");
        return feignProviderService.getOrder(orderRequest);
    }

    @Override
    public Order dealTwo() {
        return feignProviderService.findOrder(2);
    }

    @Override
    public Order dealThree() {
        OrderRequest orderRequest = new OrderRequest();
        orderRequest.setId(3);
        orderRequest.setNumber(555);
        return feignProviderService.findOrder(orderRequest);
    }

    @Override
    public Order dealFour() {
        return feignProviderService.queryOrder(4,"ORDER-FOUR");
    }
}

5、传参问题

上文也看到我们在接口类中定义了不同传参方式的API

5.1 传递JSON数据

这个也是接口开发中常用的传参规则,在Spring Boot 中通过@RequestBody标识入参。openFeign默认的传参方式就是JSON传参(@RequestBody),因此定义接口的时候可以不用@RequestBody注解标注,不过为了规范,一般都填上。

5.2 POJO表单传参

openFeign提供了一个注解@SpringQueryMap完美解决POJO表单传参。

5.3 URL携带参数

此种方式针对restful方式中的GET请求,也是比较常用请求方式。

5.4 普通传参

这种不管调用方还是被调用方都加上@RequestParam注解

6、超时处理

如果连接或者读取时间超过了默认超时时间,消费者端就会报超时。

旧版本集成Ribbon如果不设置超时时间,默认超时时间为1s,新版不用Ribbon了。

在消费端的配置文件中配置超时时间

feign:
  client:
    config:
      ## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
      default:
        connectTimeout: 5000
        readTimeout: 5000

还可以给单个服务配置超时时间,单个配置的超时时间将会覆盖全局配置。

feign:
  client:
    config:
      ## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
      default:
        connectTimeout: 5000
        readTimeout: 5000
      ## 为serviceC这个服务单独配置超时时间
      serviceC:
        connectTimeout: 30000
        readTimeout: 30000

7、开启日志增强

feign的日志级别

  • NONE: 默认的,不显示任何日志
  • BASIC: 仅记录请求方法、URL、响应状态码以及执行时间
  • HEADERS:除了BASIC 中自定义的信息外,还有请求和响应的信息头
  • FULL: 除了HEADERS中定义的信息外, 还有请求和响应的正文以及元数据。

前提条件需要在配置文件中,将日志级别设置为DEBUG。我们修改一下消费者的配置文件

feign:
  client:
    config:
      ## default 设置的全局超时时间,指定服务名称可以设置单个服务的超时时间
      default:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic
logging:
  level:
    #feign接口path
    com.example.consumer.client.FeignProviderService: debug

再次调用服务可以看到控制台有相关日志了

8、替换默认HttpClient

ApacheHttpClient和默认实现的比较

  • Feign在默认情况下使用的是JDK原生的URLConnection发送HTTP请求,没有连接池,但是对每个地址会保持一个长连接,即利用HTTP的persistence connection。
  • ApacheHttpClient实现了连接池,同时它封装了访问http的请求头,参数,内容体,响应等等,使客户端发送 HTTP 请求变得容易

添加依赖

        <!-- httpclient -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>

        <!-- feign-httpclient -->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>10.10.1</version>
        </dependency>

可以看到,默认就是开启的

9、工作原理

远程调用基本流程

其中 MethodHandler 的invoke(…)方法,主要职责是完成实际远程URL请求,然后返回解码后的远程URL的响应结果

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LoneWalker、

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值