• Feign远程接口调用


    概述

    目的:解决微服务调用问题。如何从微服务A调用微服务B提供的接口。

    特性:

    • 声明式语法,简化接口调用代码开发。
    • 像调用本地方法一样调用其他微服务中的接口。
    • 集成了Eureka服务发现,可以从注册中心中发现微服务。
    • 集成了Spring Cloud LoadBalancer,提供客户端负载均衡。
    • 从调用发起方控制微服务调用的请求时间,防止服务雪崩。

    使用Feign进行微服务调用

           
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-openfeignartifactId>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    导入依赖

           
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
            
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
            dependency>
    
            <dependency>
                <groupId>com.qfgroupId>
                <artifactId>commonartifactId>
            dependency>
    
    
            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-starter-openfeignartifactId>
            dependency>
    
            
            <dependency>
                <groupId>com.alibaba.cloudgroupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
            dependency>
        dependencies>
    
    • 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

    yml文件

    spring:
      application:
        name: feign-demo #跟配置的前缀名字
      cloud:
        nacos:
          server-addr: 127.0.0.1:8848
          config:
            file-extension: yaml
      profiles:
        active: dev #跟配置的后缀 设备名匹配
    logging:
      level:
        com.qf.feignconsumer.feign.UserFeignClient: debug
    server:
      port: 9090
    feign:
      client:
        config:
          default:
            # 建立连接的超时时间
            connectTimeout: 5000
            # 发送请求后等待接口响应结果的超时时间
            readTimeout: 3000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    创建FeignClient接口

    package com.qf.feignconsumer.feign;
    
    import com.qf.common.entity.User;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.List;
    
    @FeignClient("service-user")
    public interface UserFeignClient {
    
        /**
         * 注意,如果少加了@RequestParam,会抛出如下异常
         * Caused by: java.lang.IllegalStateException: Method has too many Body parameters
         * @param pagenum
         * @param pagesize
         * @return
         * @throws InterruptedException
         */
        @GetMapping("/user/page")
        public List<User> getUserByPage(@RequestParam("pagenum") Integer pagenum,@RequestParam("pagesize")Integer pagesize) throws InterruptedException;
    
        @GetMapping("/user/getall")
        public List<User> getAll();
    
        @PostMapping("/user/update")
        public User updateUser(@RequestBody User user);
    
        @DeleteMapping("/user/delete/{id}")
        public User deleteUser(@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

    使用主启动类

    package com.qf.feignconsumer;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    
    @SpringBootApplication
    @EnableDiscoveryClient//注册到nacos中
    @EnableFeignClients//注意:使用feign时 需要添加该注解
    public class FeignApp9090 {
        public static void main(String[] args) {
            SpringApplication.run(FeignApp9090.class,args);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    FeignController

    package com.qf.feignconsumer.controller;
    
    import com.qf.common.entity.User;
    import com.qf.common.vo.ResultVo;
    import com.qf.feignconsumer.feign.ProviderFeigngClient;
    import com.qf.feignconsumer.feign.UserFeignClient;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.List;
    
    
    @RestController
    public class FeignController {
    
        @Autowired
        UserFeignClient userFeignClient;
        @Autowired
        ProviderFeigngClient providerFeigngClient;
    
        @GetMapping("/u/test4")
        public ResultVo utest4() throws InterruptedException {
            List<User> userByPage = userFeignClient.getUserByPage(1, 2);
            return ResultVo.ok(1,"ok",userByPage);
        }
    
    
    
    
        @GetMapping("/echo")
        public ResultVo echo(String msg){
            String echo = providerFeigngClient.echo(msg);
    
            return ResultVo.ok(1,"asd",echo);
        }
    
        @GetMapping("/u/test1")
        public ResultVo utest1(){
            //使用feignclient发起微服务用
            List<User> users = userFeignClient.getAll();
            System.out.println(users);
            return ResultVo.ok(1,"ok",users);
        }
    
        @GetMapping("/u/test2")
        public ResultVo utest2(){
            //使用feignclient发起微服务用
            System.out.println("utest2");
            User user = new User(100, "luffy", "123");
            User user1 = userFeignClient.updateUser(user);
            return ResultVo.ok(1,"ok",user1);
        }
    
        @GetMapping("/u/test3")
        public ResultVo utest3(){
            //使用feignclient发起微服务用
            System.out.println("utest3");
            User user1 = userFeignClient.deleteUser(100);
            return ResultVo.ok(1,"ok",user1);
        }
    
    
    }
    
    
    • 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

    日志配置类

    package com.qf.feignconsumer.config;
    
    import feign.Logger;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class FeignConfig {
        @Bean
        public Logger.Level liver(){
            /*
             * NONE:默认的,不显示任何日志
             * BASIC:仅记录请求方法、RUL、响应状态码及执行时间
             * HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息
             * FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据
             */
            return Logger.Level.FULL;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    提供服务方的controller

    package com.qf.userprovider.controller;
    
    import com.qf.common.entity.User;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.Arrays;
    import java.util.List;
    
    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @GetMapping("/page")
        public List<User> getUserByPage(@RequestParam("pagenum") Integer pagenum,@RequestParam("pagesize")Integer pagesize) throws InterruptedException {
            User user = new User(1, "zhangsan1", "1234567");
            User user2 = new User(2, "lisi", "12345");
            Thread.sleep(5000);
            List<User> users = Arrays.asList(user, user2);
            return users;
        }
    
    
    
    
        @GetMapping("/getall")
        public List<User> getAll(){
            User user1 = new User(1, "zhangsan", "12345677");
            User user2 = new User(2, "lisi", "asdasdaas");
    
            List<User> users = Arrays.asList(user1, user2);
    
            return users;
        }
    
    
        @PostMapping("/update")
        public User updateUser(@RequestBody User user){
    
            System.out.println(user);
            //根据id更新用户
            user.setPassword("88889888");
    
            return user;
        }
    
    
        @DeleteMapping("/delete/{id}")
        public User deleteUser(@PathVariable("id") Integer id){
    
            System.out.println("要删除用户的id="+id);
            //去数据库里删除
    
            User luffy = new User(id, "luffy", "12345");
    
            return luffy;
    
        }
    
    
    }
    
    
    • 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

    Feign负载均衡

    注册中心中观察,发现Micro1微服务在Eureka注册中心中有两个服务节点

    在这里插入图片描述

    当发起feign调用时,究竟调用的是哪个节点呢?

    @RestController
    @RequestMapping("/user")
    public class UserController {
    
        @Value("${server.port}")
        String port;
    
        @GetMapping("/findAll")
        List<User> findAll(){
            System.out.println(port);
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            List<User> users = Arrays.asList(new User(1,"zhangsan", "123456", 29), new User(2,"lisi", "12345", 19));
            return users;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Feign使用的是轮询负载均衡算法,当有多个节点时,采用轮询的方式依次调用。

    Feign调用超时时间设置

    feign:
      client:
        config:
          default:
            # 建立连接的超时时间
            connectTimeout: 5000
            # 发送请求后等待接口响应结果的超时时间
            readTimeout: 10000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    将微服务的接口响应时间延长,观察接口调用,超时抛异常

        @GetMapping("/findAll")
        List<User> findAll(){
            System.out.println(port);
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            List<User> users = Arrays.asList(new User(1,"zhangsan", "123456", 29), new User(2,"lisi", "12345", 19));
            return users;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    添加全局异常处理

    @RestControllerAdvice
    public class ExHandler {
    
        @ExceptionHandler(Exception.class)
        public String handleEx(Exception e){
            return e.getMessage();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    Feign配置日志

    添加一个配置类

    @Configuration
    public class FeignConfig {
    
        @Bean
        public Logger.Level liver(){
            /*
             * NONE:默认的,不显示任何日志
             * BASIC:仅记录请求方法、RUL、响应状态码及执行时间
             * HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息
             * FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据
             */
            return Logger.Level.FULL;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    yml文件中为FeignClient接口配置日志级别

    logging:
      level:
        com.qf.feign.XXXClient: debug
    
    • 1
    • 2
    • 3
  • 相关阅读:
    去年十八,初识Java 2
    【阿旭机器学习实战】【24】信用卡用户流失预测实战
    风控策略的开发与场景应用
    C语言 0 —— 信息在计算机中的表示
    雷电模拟器dnconsole命令汇总
    【Java】x-easypdf: 一种简单易用的PDF处理库
    什么是DFT?FT、FS、DTFT、DFS、DFT的关系
    java计算机毕业设计网上拍卖系统源程序+mysql+系统+lw文档+远程调试
    wsl中安装虚拟环境virtualenv,pycharm中配置wsl解释器
    在OpenCloudOS使用snap安装.NET 6
  • 原文地址:https://blog.csdn.net/qq_53374893/article/details/132910465