ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

07-Feign远程调用

2022-07-12 15:04:08  阅读:137  来源: 互联网

标签:feign 调用 07 service Feign import order cn


二、Feign远程调用

  • 之前利用RestTemplate发起远程调用的代码
  • 存在下面的问题
    • 代码可读性差,编程体验不统一
    • 参数复杂URL难以维护
  • Feign是一个声明式的http客户端,官方地址如下所示
  • 其作用就是帮助我们优雅地实现http请求的发送,解决上面提到的问题

2.1、Feign替代RestTemplate

2.1.1、引入依赖

  • 在order-service服务的pom文件中引入feign的依赖

  • <!--feign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    

2.1.2、添加注解

  • 在order-service的启动类添加注解开启Feign的功能

  • 可以注释掉以下代码

    • @Bean
      @LoadBalanced
      public RestTemplate restTemplate() {
          return new RestTemplate();
      }
      

2.1.3、编写Feign的客户端

①、在order-service中创建一个包client

②、新建一个接口

  • 1)指定服务的名字

  • 2)指定访问地址

  • 3)方法参数的注入

  • package cn.coolman.order.client;
    
    
    import cn.coolman.order.pojo.User;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    
    @FeignClient("userservice")     // 指定服务的名字
    public interface UserFeignClient {
    
        @GetMapping("/user/{id}")
        User findById(@PathVariable("id") Long id);
    }
    
    

③、修改OrderController的代码,使用Feign的客户端去调用

  • package cn.coolman.order.web;
    
    import cn.coolman.order.client.UserFeignClient;
    import cn.coolman.order.pojo.Order;
    import cn.coolman.order.pojo.User;
    import cn.coolman.order.service.OrderService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    @RestController
    @RequestMapping("order")
    public class OrderController {
    
       @Autowired
       private OrderService orderService;
    
    //   @Autowired
    //   private RestTemplate restTemplate;
    
        @Autowired
        private UserFeignClient userFeignClient;
    
        @GetMapping("{orderId}")
        public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
            // 根据id查询订单并返回
            Order order = orderService.queryOrderById(orderId);
    
    //        User user = restTemplate.getForObject("http://localhost:8081/user/" + order.getUserId(), User.class);
    
    //        User user = restTemplate.getForObject("http://userservice/user/" + order.getUserId(), User.class);
    
            User user = userFeignClient.findById(order.getUserId());
            order.setUser(user);
    
            return order;
        }
    }
    
    

④、小结

  • 这个客户端主要是基于SpringMVC的注解来声明远程调用的信息,比如:
    • 服务名称:userservice
    • 请求方式:GET
    • 请求路径:/user/{id}
    • 请求参数:Long id
    • 返回值类型:User
  • 这样,Feign就可以帮助我们发送http请求,无需自己使用RestTemplate来发送请求了

2.1.4、测试

  • 修改order-service中的OrderService类中的queryOrderByUserId方法,使用Feign客户端代替RestTemplate
  • 访问浏览器:http://localhost:8080/order/101

2.1.5、小结

  • 使用Feign的步骤
    • ①、引入依赖
    • ②、在启动类上添加@EnableFeignClients注解,启动Feign服务
    • ③、编写FeignClient接口(目标方法的路径,服务的名称)
    • ④、使用FeignClient中定义的方法代替RestTemplate
  • 查看依赖可以知道Feign底层是以来了Ribbon的包

2.2、自定义配置

  • Feign可以支持很多的自定义配置,如下表所示

    • 类型 作用 说明
      feign.Logger.Level 修改日志级别 包含四种不同的级别:NONE(默认)、BASIC(记录什么时候发出、什么时候结束)、HEADERS(在basic基础还记录请求头信息)、FULL(记录所有的信息)
      feign.codec.Decoder 响应结果的解析器 http远程调用的结果做解析,例如解析json字符串为java对象
      feign.codec.Encoder 请求参数编码 将请求参数编码,便于通过http请求发送
      feign.Contract 支持的注解格式 默认是SpringMVC的注解
      feign.Retryer 失败重试机制 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试
    • 一般情况下,默认值就能满足正常使用,如果需要自定义,只需要创建自定义@Bean覆盖默认Bean即可

  • 下面以日志为例来演示如何自定义配置

2.2.1、配置文件方式

  • 以修改order-service为例

    • ①、基于配置文件修改Feign的日志级别可以针对单个要调用的服务

      • feign:  
          client:
            config: 
              userservice:  # 针对某个微服务的配置
                loggerLevel: BASIC #  日志级别 
        
    • ②、也可以针对所有服务

      • feign:  
          client:
            config: 
              default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
                loggerLevel: FULL #  日志级别 
        
    • PS:配置default.loggerLevel的时候idea中没有提示信息,如果两个都要配置,则优先使用userservice

  • 要看到输出的日志信息,需要将系统日志级别设置为debug才能看到

    • logging:
        level:
          cn.coolman: debug
      
    • feign:
        client:
          config:
            userservice:
              loggerLevel: BASIC
            default:
              loggerLevel: FULL
      
  • 日志的级别分为四种

    • NONE:不记录任何日志信息,这是默认值
    • BASIC:仅记录请求的方法,URL以及响应状态码和执行事件
    • HEADERS:在BASIC的基础上,额外记录了请求和响应头信息
    • FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据
  • 配置完成后,重启服务,在浏览器访问一次,对比以下配置前和配置后的控制台输出信息

    • 配置前
    • 配置后

2.2.2、Java代码方式

将上面的配置注释

  • ①、也可以基于Java代码来修改日志级别,先声明一个类放在config包中,然后声明一个Logger.Level的对象

    • package cn.coolman.order.config;
      
      import feign.Logger;
      import org.springframework.context.annotation.Bean;
      
      public class DefaultFeignConfiguration {
      
          @Bean
          public Logger.Level loggerLevel() {
              // 日志级别为BASIC,这是枚举类型
              return Logger.Level.BASIC;
          }
      }
      
      
  • ②、如果要全局生效,将其放到OrderApplication启动类的@EnableFeignClient这个注解中

    • @EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class) 
      
  • ③、如果是局部生效,则把它放到UserClient接口对应的@FeignClient这个注解中,将上面OrderApplication启动类的defaultConfiguration部分去掉

    • @FeignClient(value = "userservice", configuration = DefaultFeignConfiguration.class) 
      
  • ④、查看控制台输出信息

2.2.3、小结

  • Feign日志的类型
    • NONE:默认,不记录日志
    • BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
    • HEADERS:在BASIC基础上添加请求头
    • FULL:记录全部
  • 如何实现Feign的日志记录
    • yml文件配置
    • 编码方式配置

2.3、Feign使用优化

  • Feign底层发起http请求,依赖于其他的框架,其底层客户端实现包括
    • URLConnection:默认实现,不支持连接池。每次出啊关键连接要三次握手,结束连接还要四次挥手
    • Apache HttpClient:支持连接池
    • OKHttp:支持连接池
  • 因此提高Feign的性能的主要手段就是使用连接池代替默认的URLConnection

2.3.1、Apache的HttpClient

  • 1)引入依赖

    • 在order-service的pom文件中引入Apache的HttpClient依赖

    • <!--httpClient的依赖 -->
      <dependency>
          <groupId>io.github.openfeign</groupId>
          <artifactId>feign-httpclient</artifactId>
      </dependency>
      
  • 2)配置连接池

    • 在order-service的application.yml中添加配置,默认是开启的,所以就算没有配置也会有一些默认的配置参数

    • feign:
        httpclient:
          enabled: true # 开启feign对HttpClient的支持
          max-connections: 200 # 最大的连接数
          max-connections-per-route: 50 # 每个路径的最大连接数
      
    • PS:每个不同的微服务连接路径是不同的,如访问user-service这个微服务就是一条路径,最多有50个连接;通常最大连接数除以微服务总数,即可得出每个微服务平均占用多少个连接。后期可以根据访问性能的变化来进行调整

  • 3)在FeignClientFactoryBean的loadBalance方法中打断点

    • debug方式启动order-service服务
    • 可以看到这里的client,未配置pom.xml前使用的是默认的Client
    • 配置后底层就是Apache HttpClient

2.3.2、小结

  • Feign-HttpClient的作用
    • 默认情况Feign发起的远程调用使用的是URLConnection,URLConnection是不支持连接池的,每次远程调用都需要花费大量的时间去建立连接,使用Feign-HttpClient可以对url连接可以存储到连接池中,提高效率

2.4、最佳实践

所谓最佳实践,就是使用过程中总结的经验,得出的一种最好的方式

  • 仔细观察不难发现,Feign客户端与服务提供者的Controller代码非常相似
    • Feign客户端
    • UserController
  • 思考一种方法简化这种重复的代码编写

2.4.1、继承方式

  • 一样的代码可以通过继承来共享
    • 1)定义一个API接口,利用定义方法,并基于SpringMVC注解声明
    • 2)Feign客户端和Controller都继承该接口

优点

  • 编码简单
  • 实现了代码共享

缺点

  • 服务提供方、服务消费方紧耦合
  • 参数列表中的注解映射并不会继承,因此Controller中必须再次声明方法、参数列表的注解

2.4.2、抽取方式

  • 将Feign的Client抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用
  • 例如,将UserClient、User、Feign的默认配置都抽取到一个feign-api包中,所有微服务引用该依赖包,即可直接使用

①、抽取

  • 1)首先创建一个module,命名为feign-api,继承于cloud-demo父模块

  • 2)在feign-api中然后引入feign的starter依赖

    • <dependencies>
          <dependency>
              <groupId>org.springframework.cloud</groupId>
              <artifactId>spring-cloud-starter-openfeign</artifactId>
          </dependency>
      </dependencies>
      
  • 3)在order-service中编写的UserClient、User、DefaultFeignConfiguration都移动到feign-api项目中

  • 4)修改代码:UserClient中引入的User和包名DefaultFeignConfiguration不同了,其他类不变

    • 跟着idea操作即可,导包
  • 5)将feign-api安装到本地仓库(install)

②、使用feign-api

  • 1)首先,删除order-service中的UserClient、User、DefaultFeignConfiguration等类或接口

  • 2)在order-service的pom文件引入feign-api的依赖

    • <dependency>
          <groupId>cn.itcast.demo</groupId>
          <artifactId>feign-api</artifactId>
          <version>1.0</version>
      </dependency>
      

③、修改order-service

  • 1)修改Order
  • 2)修改Orderservice
  • 3)启动类中如果用到了DefaultFeignConfiguration也要改一下

这三步都是因为导包的问题,比较简单,这里就不演示了,跟着idea操作也能解决

④、重启测试

  • 重新运行程序后,发现服务报错了,报错信息如下所示
  • 这是因为UserClient现在在cn.coolman.feign.client包下,而order-service的@EnableFeignClients注解默认扫描的是cn.coolman.order包和它的子包,不在同一个父包中,无法扫描到UserClient

⑤、解决扫描包问题

  • 方式一

    • 指定Feign应该扫描的包:对整个包下的所有接口生成代理对象

    • @EnableFeignClients(basePackages = "cn.itcast.feign.client")
      
  • 方式二

    • 指定需要加载的Client接口:对指定的接口生成代理对象

    • @EnableFeignClients(clients = {UserClient.class})
      
  • 测试

标签:feign,调用,07,service,Feign,import,order,cn
来源: https://www.cnblogs.com/OnlyOnYourself-lzw/p/16458206.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有