• 微服务入门:http客户端Feign


    http客户端Feign

    一、RestTemplate方式调用存在的问题

        @Autowired
        private RestTemplate restTemplate;
    
        public Order queryOrderById(Long orderId) {
            // 1.查询订单
            Order order = orderMapper.findById(orderId);
            //2.利用RestTemplate查询用户
            String url = "http://userservice/user/"+order.getUserId();
            //restTemplate传递一个User.clss过去目的是为了返回不是一个json,而是返回一个实体类
            User user = restTemplate.getForObject(url, User.class);
            //3.封装user信息
            order.setUser(user);
            // 4.返回
            return order;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在使用RestTemplate发送远程调用的时候,可以看出来这段代码写的并不好

    1. 代码可读性差,编程体验不统一
    2. 参数复杂URL难以维护

    因此Feign就出现了,其官方地址是https://github.com/OpenFeign/feign

    Feign可以帮助我们更加优雅地实现http请求的发送,解决上面提到的问题


    二、Feign使用步骤

    1. 引入依赖

    	<dependency>
    		<groupId>io.github.openfeign</groupId>
    		<artifactId>feign-httpclient</artifactId>
    	</dependency>
    
    • 1
    • 2
    • 3
    • 4

    2. 在启动类中开启Feign功能

    @MapperScan("cn.itcast.order.mapper")
    @SpringBootApplication
    @EnableFeignClients //开启Feign功能
    public class OrderApplication {
        public static void main(String[] args) {
            SpringApplication.run(OrderApplication.class, args);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3. 编写Feign客户端

    @FeignClient("userservice")
    public interface UserFeign {
        @GetMapping("/user/{id}")
        User findById(@PathVariable("id") Long id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    其主要是基于SpringMVC的注解来声明远程调用信息

    • 服务名:userservice
    • 请求方式:GET
    • 请求路径:/user/{id}
    • 请求参数:Long id
    • 返回值类型:User
    String url = "http://userservice/user/"+order.getUserId();
    
    • 1

    4. 用Feign客户端代替RestTemplate

    @Autowired
    UserFeign userFeign;
    
    public Order queryOrderById(Long orderId){
    	// 1.查询订单
    	Order order = orderMapper.findById(orderId);
    	// 2.用feign获取
    	User user = userFeign.findById(order.getUserId());
    	//3.封装user信息
    	order.setUser(user);
    	// 4.返回
    	return order;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    三、自定义Feign的配置

    Feign运行自定义配置来覆盖默认配置,可以修改的配置如下:

    类型作用说明
    feign.Logger.Level修改日志级别包含四种不同的级别:NONE、BASIC、HEADERS、FULL
    feign.codec.Decoder响应结果的解析器http远程调用的结果做解析,例如解析json字符串为java对象
    feign.codec.Encoder请求参数编码将请求参数编码,便于通过http请求发送
    feign. Contract支持的注解格式默认是SpringMVC的注解
    feign. Retryer失败重试机制请求失败的重试机制,默认是没有,不过会使用Ribbon的重试

    但是这其中最常用的是修改日志级别


    1. 通过配置文件方式修改Feign日志级别

    以下这种配置方式全局生效

    #配置日志
    feign:
      client:
        config:
          default: #default全局配置
            loggerLevel: BASIC # 日志级别 BASIC就是基本的请求和响应信息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    以下这种配置方式局部生效

    #配置日志
    feign:
      client:
        config:
          userservice: #default全局配置
            loggerLevel: BASIC # 日志级别 BASIC就是基本的请求和响应信息
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2. 通过Java代码修改Feign日志级别

    新建一个类,声明一个Bean

    public class DefaultFeignConfiguration {
        @Bean
        public Logger.Level feignLogLevel(){
            return Logger.Level.BASIC;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 全局配置,将它放到@EnableFeignClients这个注解中

      @EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
      
      • 1
    • 局部配置,将它放到@FeignClient这个注解中

      @FeignClient(value = "userservice", configuration = DefaultFeignConfiguration.class)
      
      • 1

    四、Feign的性能优化

    在Feign底层的客户端实现:

    • URLConnection:默认实现,不支持连接池
    • Apache HttpClient:支持连接池
    • OKHttp:支持连接池

    因此优化Feign的性能包括:

    • 使用连接池代替默认的URLConnection
    • 日志级别,最好用basic或none

    1. 添加HttpClient的支持

    首先 引入依赖

    <dependency>
    	<groupId>io.github.openfeign</groupId>
    	<artifactId>feign-httpclient</artifactId>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4

    配置连接池

    #配置日志
    feign:
      client:
        config:
          default: #default全局配置
            loggerLevel: BASIC # 日志级别 BASIC就是基本的请求和响应信息
      httpclient:
        enabled: true #开启feign对HttpClient的支持
        max-connections: 200 #最大连接
        max-connections-per-route: 50 #每个路径最大连接数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    五、Feign的最佳实践

    1. 方式一(继承)

    给消费者的FeignClient和提供者的controller定义统一的父接口作为标准

    也就是说,FeignClient和Controller都是同一个方法,他们的请求方式,请求参数都一样,因此可以额外定义一个接口,然后FeignClient和Controller继承这个接口就可以了

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vS372fof-1656147830852)(http客户端Feign.assets/image-20220625165630716.png)]

    但是这样的方式会有以下问题:

    • 服务紧耦合
    • 父接口参数列表中的映射不会被继承

    2. 方式二(抽取)

    将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给所有消费者使用

    也就是说额外添加一个模块,把接口中的相关东西放到那个模块中,需要用到这个模块的话,那么就在pom.xml中引入这个模块

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sUp0jefx-1656147830854)(http客户端Feign.assets/image-20220625165949272.png)]

    实现最佳实践方式二的步骤如下:

    1.首先创建一个module,命名为feign-api,然后引入feign的starter依赖

    2.将order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中

    3.在order-service中引入feign-api的依赖

    4.修改order-service中的所有与上述三个组件有关的import部分,改成导入feign-api中的包

    5.重启测试

    但是这样启动的话会报错,因此FeignClient不在SpringBootApplication的扫描包范围时,这些FeignClient无法使用

    解决方法:

    //方式一:指定FeignClient所在包
    @EnableFeignClients(basePackages = "cn.itcast.feign.clients")
    
    • 1
    • 2
    //方式二:指定FeignClient字节码
    @EnableFeignClients(clients = {UserClient.class})
    
    • 1
    • 2

  • 相关阅读:
    Java编程技巧:if-else优化实践总结归纳
    学到一招 chrome 浏览器 debug 悬浮样式
    常见问题汇总
    Android 12(S) 图像显示系统 - BufferQueue/BLASTBufferQueue之初识(六)
    python:切分多个串联但单个内部按大小排列数据列表
    基于docker commit和Dockerfile为镜像添加ssh服务
    Autosar教程-Mcal教程-GPT配置教程
    20220803NOI模拟赛--考后总结
    DNSLog原理及代码实现
    leetcode 1523. 在区间范围内统计奇数数目
  • 原文地址:https://blog.csdn.net/weixin_51146329/article/details/125461653