栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Feign快速入门

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Feign快速入门

Feign快速入门

简介:Feign是声明式(注解)web服务客户端。Feign是一个远程调用的组件(接口、注解)完成http调用,Feign集成了ribbon、ribbon里面集成了eureka。使用feign需要创建一个接口添加feign注解。

依旧沿用之前的项目,创建一个feign的空项目,再创建springboot项目,springboot版本2.3.12.RELEASE,springcloud版本Hoxton.SR12,基本依赖有eureka、spring web、Lombok

  1. 创建一个order-service项目代码:

    @RestController
    public class OrderController {
    
        @GetMapping("doOrder")
        public String doOrder(){
            return "订单接口";
        }
    }
    
    server:
      port: 8080
    spring:
      application:
        name: order-service
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka
    
    @SpringBootApplication
    @EnableEurekaClient
    public class OrderServiceApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(OrderServiceApplication.class, args);
        }
    
    }
    
  2. 创建user-service项目代码,这个项目增加一个feign依赖:

    server:
      port: 8081
    spring:
      application:
        name: user-service
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:8761/eureka
    
    @SpringBootApplication
    @EnableEurekaClient
    @EnableFeignClients // 开启feign的客户端功能
    public class UserServiceApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(UserServiceApplication.class, args);
        }
    
    }
    
    @RestController
    public class UserController {
    
        @Autowired
        public UserOrderFeign userOrderFeign;
    
        
        @GetMapping("userDoOrder")
        public String userDoOrder(){
            System.out.println("用户请求");
            //发起一个远程调用 请求order-service
            String s = userOrderFeign.doOrder();
            return  s;
        }
    }
    

    feign接口:

    @FeignClient(value = "order-service")
    public interface UserOrderFeign {
        
        @GetMapping("doOrder")
        String doOrder();
    
    }
    
  3. 把eureka-server和上面的两个新代码运行起来访问localhost:8081/userDoOrder

  4. 修改order-service控制层代码

    @RestController
    public class OrderController {
    
        @GetMapping("doOrder")
        public String doOrder(){
            try {
                //模拟操作数据库的耗时
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "订单接口";
        }
    }
    

    重启后,再次访问localhost:8081/userDoOrder 会发现报500 ,控制台报Read timed out超时,这是因为feign封装了ribbon,ribbon默认等待时间1000毫秒,所以超过1s直接报错超时

  5. 增加user-service配置

    # feign只是封装了远程调用的功能,底层还是ribbon,所以修改ribbon的时间
    ribbon:
      ReadTimeout: 3000   # 调用超时时间(毫秒)
      ConnectTimeout: 3000  # 连接服务的超时时间(毫秒)
    

    重启user-service,访问localhost:8081/userDoOrder,此时正常

  6. Feign简单实现

    主要是通过动态代理,这里重写一下invoke方法。获取注解的value再拼接url,最后使用restTemplate把拼好的url放进去即可。这里的url其实还是接口名的形式,ribbon会再处理一下把接口变成ip。

    @SpringBootTest
    class UserServiceApplicationTests {
        @Autowired
        private RestTemplate restTemplate;
    
        @Test
        void contextLoads() {
            UserOrderFeign o = (UserOrderFeign) Proxy.newProxyInstance(UserController.class.getClassLoader(), new Class[]{UserOrderFeign.class}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("重写了invoke");
                    //拿到对方的ip和端口 并且拿到这个方法上面注解的值
                    String name = method.getName();
                    GetMapping annotation = method.getAnnotation(GetMapping.class);
                    String[] paths = annotation.value();
                    String path = paths[0];
                    Class declaringClass = method.getDeclaringClass();
                    FeignClient annotation1 = declaringClass.getAnnotation(FeignClient.class);
                    String applicationName = annotation1.value();
                    String url = "http://" + applicationName + "/" + path;
                    String forObject = restTemplate.getForObject(url, String.class);
                    return forObject;
                }
            });
            String s = o.doOrder();
            System.out.println(s);
        }
    
    }
    
  7. Feign参数处理

    order-service添加一个新的controller

    @RestController
    public class ParamController {
    
        @GetMapping("testUrl/{name}/{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(order);
            System.out.println(name);
            return "ok";
        }
    }
    

    order实体类

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    public class Order {
        private Integer id;
        private String name;
        private Double price;
        private Date time;
    
    }
    

    user-service controller添加一个方法

    @GetMapping("testParam")
    public String testParam(){
        String testUrl = userOrderFeign.testUrl("testUrl", 18);
        System.out.println(testUrl);
        String oneParam = userOrderFeign.oneParam("oneParam");
        System.out.println(oneParam);
        String twoParam = userOrderFeign.twoParam("twoParam", 18);
        System.out.println(twoParam);
        Order order = Order.builder().name("abc").price(100D).time(new Date()).id(1).build();
        String oneObj = userOrderFeign.oneObj(order);
        System.out.println(oneObj);
        String oneObjOneParam = userOrderFeign.oneObjOneParam(order, "oneObjOneParam");
        System.out.println(oneObjOneParam);
        return "ok";
    }
    

    实体类也要粘过来

    接口添加代码

    @GetMapping("testUrl/{name}/{age}")
    public String testUrl(@PathVariable("name")String name, @PathVariable("age")Integer age);
    
    @GetMapping("oneParam")
    public String oneParam(@RequestParam(required = false) String name);
    
    @GetMapping("twoParam")
    public String twoParam(@RequestParam(required = false) String name,@RequestParam(required = false)Integer age);
    
    @PostMapping("oneObj")
    public String oneObj(@RequestBody Order order);
    
    @PostMapping("oneObjOneParam")
    public String oneObjOneParam(@RequestBody Order order,@RequestParam("name") String name);
    
  8. 测试传递时间参数

    order-service controller添加一个方法

    @GetMapping("testTime")
    public String testTime(@RequestParam Date date){
        System.out.println(date);
        return "ok";
    }
    

    user-service controller添加方法

    @GetMapping("time")
    public String testTime(){
        Date date = new Date();
        System.out.println(date);
        String s = userOrderFeign.testTime(date);
        return s;
    }
    

    feign接口添加

    @GetMapping("testTime")
    public String testTime(@RequestParam Date date);
    

    访问http://localhost:8081/time结果如下

    user-service Mon Jul 11 17:18:57 CST 2022

    order-service Tue Jul 12 07:18:57 CST 2022

    会发现有14小时差距,所以最好不要单独传递时间参数

    可以转成字符串 或者 使用LocalDate 年月日

    但是使用LocalDateTime 会丢失秒

  9. Feign日志功能

    Feign的Logger类有四个日志级别

    public enum Level {
        
        NONE,
        
        BASIC,
        
        HEADERS,
        
        FULL
      }
    
    • none 无日志
    • basic 记录请求方法、url、响应状态码、时间
    • headers 记录请求和响应的主要信息
    • full 最高的日志级别,记录请求和响应的头、体、元数据
  10. 如何开启Feign功能

    修改配置文件

    logging:
      level:
        com.example.userservice.feign.UserOrderFeign: debug # 打印该接口下的日志
    

    修改启动类

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

aders 记录请求和响应的主要信息

  • full 最高的日志级别,记录请求和响应的头、体、元数据
  1. 如何开启Feign功能

    修改配置文件

    logging:
      level:
        com.example.userservice.feign.UserOrderFeign: debug # 打印该接口下的日志
    

    修改启动类

    @Bean
    public Logger.Level level(){
        return Logger.Level.FULL;
    }
    
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1014771.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号