• SpringCloud学习笔记(四)


    SpringCloud学习笔记(四)

    1.说在前面

    上 一 节 我 们 讲 到 Ribbon 做 了 负 载 均 衡 , 用 Eureka-Client 来 做 服 务 发 现 , 通 过RestTemplate 来完成服务调用,但是这都不是我们的终极方案,终极方案是使用 OpenFeign

    2.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 CloudLoadBalancer,以在使用 Feign 时提供负载平衡的 http 客户端。

    Feign 是一个远程调用的组件 (接口,注解) http 调用的
    Feign 集成了 ribbon ribbon 里面集成了 eureka

    3.OpenFeign 快速入门

    3.1 本次调用的设计图

    在这里插入图片描述

    在这里插入图片描述

    3.2 启动一个 eureka-server 服务,这里不重复演示,参考 eureka

    文档

    3.3 先创建 01-order-service,选择依赖

    在这里插入图片描述添加eureka Client依赖、lombok依赖、spring Web依赖。
    修改yml配置文件
    在这里插入图片描述

    3.4 创建 02-user-consumer,选择依赖

    添加lombok、web、eureka client、openFeign依赖。
    在这里插入图片描述修改yml配置文件

    server:
      port: 8081
    spring:
      application:
        name: consumer-user-service
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka
      instance:
      instance-id: ${spring.application.name}:${server.port}
      prefer-ip-address: true
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.5需求分析以及相应代码编写

    需求:
    创建一个消费者去消费订单表的接口(也就是访问消费者接口,能够直接访问到订单的接口)

    3.5.1 01-order-service 创建 controller

    在这里插入图片描述OrderController

    package com.jierlung.controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class OrderController {
    
    
        @GetMapping("doOrder")
        public String doOrder() {
            System.out.println("有用户来下单了");
            return "下单成功";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    3.5.2 02-user-consumer 创建 controller和接口

    创建接口

    在这里插入图片描述UserOrderFeign

    package com.jierlung.feign;
    
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    
    @FeignClient(value = "provider-order-service")
    public interface UserOrderFeign {
        @GetMapping("doOrder")
        public String doOrder();
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    创建controller
    在这里插入图片描述
    UserController

    package com.jierlung.controller;
    
    import com.jierlung.feign.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
        private UserOrderFeign userOrderFeign;
    
        @GetMapping("doUser")
        public String doOrder() {
            System.out.println("有用户进来了");
            String s = userOrderFeign.doOrder();
            return s;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在启动类上添加注解
    在这里插入图片描述

    3.6访问测试

    在这里插入图片描述

    3.7调用超时设置

    因 为 ribbon 默 认 调 用 超 时 时 长 为 1s , 可 以 修 改 , 超 时 调 整 可 以 查 看
    DefaultClientConfigImpl

    ribbon: #feign 默认调用 1s 超时
    	ReadTimeout: 5000 # 修改调用时长为 5s
    	ConnectTimeout: 5000 # 修改连接时长为 5s
    
    • 1
    • 2
    • 3

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

    4.1 说在前面

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

    1. 通过 URL 传参数,GET 请求,参数列表使用@PathVariable(“”)
    2. 如果是 GET 请求,每个基本参数必须加@RequestParam(“”)
    3. 如果是 POST 请求,而且是对象集合等参数,必须加@Requestbody 或者@RequestParam

    4.2 修改 provider-order-service

    4.2.1 创建 BaseResult 类
    package com.jierlung.domain;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.io.Serializable;
    
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class BaseResult implements Serializable {
        private Integer code;
        private String msg;
        private Object data;
    
        public static BaseResult success(Integer code, String msg, Object data) {
            BaseResult baseResult = new BaseResult();
            baseResult.setCode(code);
            baseResult.setData(data);
            baseResult.setMsg(msg);
            return baseResult;
        }
    }
    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    4.2.2 创建 Order 类
    package com.jierlung.domain;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.io.Serializable;
    import java.util.Date;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Order implements Serializable {
        private String orderSn;
        private String orderName;
        private String orderDetail;
        private Date orderTime;
        private String userId;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    4.2.3 创建 TestParamController 类
    @RestController
    public class TestParamController {
    /**
    * 测试单个参数
    *
    * @param name
    * @return
    */
    @GetMapping("testOneParam")
    public BaseResult oneParam(@RequestParam("name") String name) {
    System.out.println(name);
    return BaseResult.success(200, "成功", "ok");
    }
    /**
    * 测试两个参数
    *
    * @param name
    * @param age
    * @return
    */
    @PostMapping("testTwoParam")
    public BaseResult twoParam(@RequestParam("name") String name,
    
    @RequestParam("age") Integer age) {
    System.out.println(name + ":" + age);
    return BaseResult.success(200, "ok", "ok");
    }
    /**
    * 测试一个对象的传参
    *
    * @param order
    * @return
    */
    @PostMapping("testObjectParam")
    public BaseResult objectParam(@RequestBody Order order) {
    System.out.println(order);
    return BaseResult.success(200, "ok", order);
    }
    /**
    * 测试一个对象 一个参数
    *
    * @param order
    * @param name
    * @return
    */
    @PostMapping("testOneObjectOneParam")
    public BaseResult oneObjectOneParam(@RequestBody Order order,
    @RequestParam String name) {
    System.out.println(order);
    System.out.println(name);
    return BaseResult.success(200, "ok", order);
    }
    /**
    * 测试 url 传参
    *
    www.bjpowernode.com 13 / 29 Copyright©动力
    节点
    * @param id
    * @return
    */
    @GetMapping("testUrlParam/{id}")
    public BaseResult testUrlParam(@PathVariable("id") Integer id) {
    System.out.println(id);
    return BaseResult.success(200, "ok", id);
    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    4.3 修改 consumer-user-service

    4.3.1 将 Order 类和 BaseResult 类拷贝过来,后面会抽到公共模块里
    4.3.2 修改 UserOrderFeign 接口
    package com.jierlung.feign;
    
    import com.jierlung.domain.BaseResult;
    import com.jierlung.domain.Order;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.*;
    
    @FeignClient(value = "provider-order-service")
    public interface UserOrderFeign {
    
    
        /**
         * 远程调用下单的方法
         *
         * @return
         */
        @RequestMapping("doOrder")
        String doOrder();
    
        /**
         * 测试单个参数
         *
         * @param name
         * @return
         */
        @GetMapping("testOneParam")
        public BaseResult oneParam(@RequestParam("name") String name);
    
        /**
         * 测试两个参数
         *
         * @param name
         * @param age
         * @return
         */
        @PostMapping("testTwoParam")
        public BaseResult twoParam(@RequestParam("name") String name,
                                   @RequestParam("age") Integer age);
    
        /**
         * 测试一个对象的传参
         *
         * @param order
         * @return
         */
        @PostMapping("testObjectParam")
        public BaseResult objectParam(@RequestBody Order order);
    
        /**
         * 测试一个对象 一个参数
         *
         * @param order
         * @param name
         * @return
         */
        @PostMapping("testOneObjectOneParam")
        public BaseResult oneObjectOneParam(@RequestBody Order order,
                                            @RequestParam String name);
    
        /**
         * 测试 url 传参
         *
         * @param id
         * @return
         */
        @GetMapping("testUrlParam/{id}")
        public BaseResult testUrlParam(@PathVariable("id") Integer id);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    4.3.3 创建 TestController 类
    @RestController
    public class TestController {
    
        @Autowired
        private UserOrderFeign userOrderFeign;
    
        @RequestMapping("testFeignParam")
        public String testFeignParam() {
            // 测试一个参数
            BaseResult result1 = userOrderFeign.oneParam("bjpowernode");
            System.out.println(result1);
            System.out.println("--------------------------------------------------");
            // 测试多个参数
            BaseResult result2 = userOrderFeign.twoParam("bjpowernode", 666);
            System.out.println(result2);
            System.out.println("--------------------------------------------------");
            // 测试一个对象
            Order order = new Order("111", "牛排", "一份牛排 256g", new Date(), "159357");
            BaseResult result3 = userOrderFeign.objectParam(order);
            System.out.println(result3);
            System.out.println("--------------------------------------------------");
            // 测试 url 传参
            BaseResult result4 = userOrderFeign.testUrlParam(999);
            System.out.println(result4);
            System.out.println("--------------------------------------------------");
            // 测试一个对象 一个参数
            BaseResult result5 = userOrderFeign.oneObjectOneParam(order,
                    "bjpowernodebjpowernode");
            System.out.println(result5);
            System.out.println("--------------------------------------------------");
            return "ok";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    4.3.4 测试调用

    在这里插入图片描述在这里插入图片描述

    在这里插入图片描述

    4.3.5 时间日期参数问题

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

    1. 使用字符串传递参数,接收方转换成时间类型(推荐使用)不要单独传递时间
    2. 使用 JDK8 的 LocalDate(日期) 或 LocalDateTime(日期和时间,接收方只有秒,没有毫秒)
    3. 自定义转换方法
      传参总结:
      get 请求只用来传递基本参数 而且加注解@RequestParam
      post 请求用来传递对象参数 并且加注解@RequestBody

    6.OpenFeign 总结

    OpenFeign 主要基于接口和注解实现了远程调用
    源码总结:面试

    1. OpenFeign 用过吗?它是如何运作的?
      在主启动类上加上@EnableFeignClients 注解后,启动会进行包扫描,把所有加了
      @FeignClient(value=”xxx-service”)注解的接口进行创建代理对象通过代理对象,使用
      ribbon 做了负载均衡和远程调用
    2. 如何创建的代理对象?
      当 项 目 在 启 动 时 , 先 扫描 , 然 后 拿 到 标 记了 @FeignClient 注 解的 接 口 信息 , 由ReflectiveFeign 类的 newInstance 方法创建了代理对象 JDK 代理
    3. OpenFeign 到底是用什么做的远程调用?
      使用的是 HttpURLConnection (java.net)
    4. OpenFeign 怎么和 ribbon 整合的?
      在代理对象执行调用的时候

    7.OpenFeign 其他

    7.1 OpenFeign 的日志功能

    从前面的测试中我们可以看出,没有任何关于远程调用的日志输出,如请头,参数
    Feign 提供了日志打印功能,我们可以通过配置来调整日志级别,从而揭开 Feign 中 Http 请求的所有细节

    7.1.1 OpenFeign 的日志级别

    NONE 默认的,不显示日志
    BASE 仅记录请求方法,URL ,响应状态码及执行时间
    HEADERS 在 BASE 之上增加了请求和响应头的信息
    FULL 在 HEADERS 之上增加了请求和响应的正文及无数据

    7.1.2 创建配置类
    @Configuration
    public class FeignConfig {
        @Bean
        Logger.Level feignLogger() {
            return Logger.Level.FULL;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    7.1.3 修改配置文件

    在这里插入图片描述

  • 相关阅读:
    LeetCoed617:合并二叉树
    爬虫的法律风险是什么?以及合法使用爬虫技术的建议。
    地震勘探——相关概念(一)
    【无标题】
    【Java数据结构 -- 二叉树有关面试OJ题2】
    暂存5暂存5暂存5
    【总结】助力2022年全国大学生数学建模 — 智能算法总结篇(万字总结)
    订单超时自动取消订单实现策略
    干货 :医疗企业渠道管理实战手册:策略、平台建设、CRM解决方案
    y140.第八章 Servless和Knative从入门到精通 -- Serving及实践(四)
  • 原文地址:https://blog.csdn.net/qq_52166656/article/details/128006035