OpenFeign

1.说在前面#

上 一 节 我 们 讲 到 Ribbon 做 了 负 载 均 衡 , 用 Eureka-Client 来 做 服 务 发 现 , 通 过

RestTemplate 来完成服务调用,但是这都不是我们的终极方案,终极方案是使用 OpenFeign

1.OpenFeign 简介#

https://docs.spring.io/spring-cloud-openfeign/docs/2.2.4.RELEASE/reference/html/#spring-cloud-feign

Feign 是声明性(注解)Web 服务客户端。它使编写 Web 服务客户端更加容易。要使用 Feign****,

请创建一个接口并对其进行注解。它具有可插入注解支持,包括 Feign 注解和 JAX-RS 注解。

Feign 还支持可插拔编码器和解码器。Spring Cloud 添加了对 Spring MVC 注解的支持,并

支持使用 HttpMessageConverters,Spring Web 中默认使用的注解。Spring Cloud 集成

了 Ribbon 和 Eureka 以及 Spring Cloud LoadBalancer,以在使用 Feign 时提供负载平衡

http 客户端

Feign 是一个远程调用的组件 (接口,注解) http 调用的

Feign 集成了 ribbon

ribbon 里面集成了 eureka

2.OpenFeign 快速入门#

2.1 使用OpenFeign#

  1. 使用OpenFeign 创建接口
package com.example.userservice.fegin;


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

/**
 * @FeignClient(value = "order-service")
 * value 就是提供者的应用名称
 */
@FeignClient(value = "order-service")
public interface UserOrderFeign {

    /**
     * 你需要调用哪个controller  就写它的方法签名
     * 方法签名(就是包含一个方法的所有的属性)
     *
     * @return
     */
    @GetMapping("doOrder")
    String doOrder();

}

2.调用接口

package com.example.userservice.controller;

import com.example.userservice.fegin.UserOrderFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;


@RestController
public class UserController {

    @Autowired
    public UserOrderFeign userOrderFeign;

    /**
     * 总结
     * 浏览器(前端)-------> user-service(/userDoOrder)-----RPC(feign)--->order-service(/doOrder)
     * feign的默认等待时间时1s
     * 超过1s就在直接报错超时
     *
     * @return
     */
    @GetMapping("userDoOrder")
    public String userDoOrder() {
        System.out.println("有用户进来了");
        String s = userOrderFeign.doOrder();
        return s;
    }
}

  1. 修改启动类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients // 开启feign的客户端功能 才可以帮助我们发起调用
public class UserServiceApplication {

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

}

2.2 设置超时设置#

ribbon:
  ReadTimeout: 3000 # 给3s超时时间
  ConnectTimeout: 3000 # 链接服务的超时时间

2.3 OpenFeign 通过JDK动态代理实现#

 /**
     * 接口是不能做事情的
     * 如果想做事 必须要有对象
     * 那么这个接口肯定是被创建出代理对象的
     * 动态代理 jdk(java interface 接口 $Proxy )  cglib(subClass 子类)
     * jdk动态代理 只要是代理对象调用的方法必须走 java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
     */

4.OpenFeign 调用参数处理(开发重点)#

4.1 说在前面#

Feign 传参确保消费者和提供者的参数列表一致 包括返回值 方法签名要一致

  1. 通过 URL 传参数,GET 请求,参数列表使用@PathVariable(“”)

  2. 如果是 GET 请求,每个基本参数必须加@RequestParam(“”)

  3. 如果是 POST 请求,而且是对象集合等参数,必须加@Requestbody 或者@RequestParam

4.2 参数配置#

  1. 传参
/**
 * @FeignClient(value = "order-service")
 * value 就是提供者的应用名称
 */
@FeignClient(value = "order-service")
public interface UserOrderFeign {

    /**
     * 你需要调用哪个controller  就写它的方法签名
     * 方法签名(就是包含一个方法的所有的属性)
     *
     * @return
     */
    @GetMapping("doOrder")
    String doOrder();


    @GetMapping("testUrl/{name}/and/{age}")
    String testUrl(@PathVariable("name") String name, @PathVariable("age") Integer age) ;

    @GetMapping("oneParam")
    String oneParam(@RequestParam(required = false) String name) ;


    @GetMapping("twoParam")
    String twoParam(@RequestParam(required = false) String name, @RequestParam(required = false) Integer age);

    @PostMapping("oneObj")
    String oneObj(@RequestBody Order order) ;


    @PostMapping("oneObjOneParam")
    String oneObjOneParam(@RequestBody Order order,@RequestParam("name") String name) ;


}
  1. Controller

    @RestController
    public class ParamController {
    
        @GetMapping("testUrl/{name}/and/{age}")
        public String testUrl(@PathVariable("name") String name, @PathVariable("age") Integer age) {
            System.out.println(name + ":" + age);
            return "ok";
        }
    
        @GetMapping("oneParam")
        public String oneParam(@RequestParam(required = false) String name) {
            System.out.println(name);
            return "ok";
        }
    
    
        @GetMapping("twoParam")
        public String twoParam(@RequestParam(required = false) String name, @RequestParam(required = false) Integer age) {
            System.out.println(name);
            System.out.println(age);
            return "ok";
        }
    
        @PostMapping("oneObj")
        public String oneObj(@RequestBody Order order) {
            System.out.println(order);
            return "ok";
        }
    
    
        @PostMapping("oneObjOneParam")
        public String oneObjOneParam(@RequestBody Order order,@RequestParam("name") String name) {
            System.out.println(name);
            System.out.println(order);
            return "ok";
        }
    
    
        ////////////////// 单独传递时间对象
    
        @GetMapping("testTime")
        public String testTime(@RequestParam Date date){
            System.out.println(date);
            return "ok";
        }
    }
    
    
  2. 调用openFegin

    @GetMapping("testParam")
        public String testParam(){
            String cxs = userOrderFeign.testUrl("cxs", 18);
            System.out.println(cxs);
    
            String t = userOrderFeign.oneParam("老唐");
            System.out.println(t);
    
            String lg = userOrderFeign.twoParam("雷哥", 31);
            System.out.println(lg);
    
            Order order = Order.builder()
                    .name("牛排")
                    .price(188D)
                    .time(new Date())
                    .id(1)
                    .build();
    
            String s = userOrderFeign.oneObj(order);
            System.out.println(s);
    
            String param = userOrderFeign.oneObjOneParam(order, "稽哥");
            System.out.println(param);
            return "ok";
        }
    

4.3 时间日期参数问题#

使用 feign 远程调用时,单独传递 Date 类型,接收方的时间会相差 14 个小时,是因为时区造成

的。

解决办法:

/**
     * Sun Mar 20 10:24:13 CST 2022
     * Mon Mar 21 00:24:13 CST 2022  +- 14个小时
     * 1.不建议单独传递时间参数。bao'guo对象里面
     * 2.转成字符串   2022-03-20 10:25:55:213 因为字符串不会改变
     * 3.jdk LocalDate 年月日    LocalDateTime 会丢失毫秒
     * 4.改feign的源码
     *
     * @return
     */

5.OpenFeign 总结#

OpenFeign 主要基于接口和注解实现了远程调用

源码总结:面试

  1. OpenFeign 用过吗?它是如何运作的?

在主启动类上加上@EnableFeignClients 注解后,启动会进行包扫描,把所有加了

@FeignClient(value=”xxx-service”)注解的接口进行创建代理对象通过代理对象,使用

ribbon 做了负载均衡和远程调用

  1. 如何创建的代理对象?

当 项 目 在 启 动 时 , 先 扫 描 , 然 后 拿 到 标 记 了 @FeignClient 注 解 的 接 口 信 息 , 由

ReflectiveFeign 类的 newInstance 方法创建了代理对象 JDK 代理

  1. OpenFeign 到底是用什么做的远程调用?

使用的是 HttpURLConnection (

java.net)

  1. OpenFeign 怎么和 ribbon 整合的?

在代理对象执行调用的时候

6.OpenFeign 日志#

6.1 OpenFeign 的日志功能#

从前面的测试中我们可以看出,没有任何关于远程调用的日志输出,如请头,参数

Feign 提供了日志打印功能,我们可以通过配置来调整日志级别,从而揭开 Feign 中 Http 请

求的所有细节

6.1.1 OpenFeign 的日志级别

NONE 默认的,不显示日志

BASE 仅记录请求方法,URL ,响应状态码及执行时间

HEADERS 在 BASE 之上增加了请求和响应头的信息

FULL 在 HEADERS 之上增加了请求和响应的正文及无数据

设置日志级别

  @Bean
    public Logger.Level level(){
        return Logger.Level.FULL;
    }

开启日志

logging:
  level:
    com.example.userservice.fegin.UserOrderFeign: debug  # 我需要答应这个接口下面的日志 

作者:Esofar

出处:https://www.cnblogs.com/firsthelloworld/p/17439940.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   我不想学编丿程  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示