• 【微服务】七. http客户端Feign


    7.1 基于Feign远程调用

    RestTimeplate方式调用存在的问题

    先来看以前利用RestTemplate发起远程调用的代码:

    String  url = "http://userservice/user"+order.getUserId();
    User user = restTemplate.getForObject(url,User.class);
    
    • 1
    • 2

    存在下面的问题:

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

    Feign的介绍

    Feign是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign
    其作用就是帮助我们优雅的实现http请求的发送,解决上面的问题。

    定义和使用Feign客户端
    使用Feign的步骤如下:

    • 引入依赖
    <dependency>
    	<groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-openfeignartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 在order-service的启动类添加注解开启Feign的功能:
    @EnableFeignClients  -- 开启feign注解
    @MapperScan("cn.itcast.order.mapper")
    @SpringBootApplication
     public class OrderApplication{
         public static void main(String[] args){
             SpringApplication.run(OrderApplication.class,args);
         }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 编写Feign客户端
    @FeignClient("userservice")
    public interface UserClient{
        @GetMapping("/user/{id}")
        User findById(@PathVariable("id") Long id);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    主要是基于SpringMVC的注解来声明远程调用的信息,比如:

    • 服务名称:userservice
    • 请求方式:GET
    • 请求路径:/user/{id}
    • 请求参数:Long id
    • 返回值类型:User
    1. 用Feign客户端代替RestTemplate
    @Autowired
    private UserClient userClient;
    
    public Order queryOrderById(Long orderId){
    	// 1. 查询订单
    	Order order = orderMapper.findById(orderId);
    	// 2. 利用Feign发起http请求,查询用户
    	User user = userClient.findById(order.getUserId());
    	// 3. 封装User到Order
    	order.setUser(user);
    	// 4. 返回
    	return order; 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    实际操作:
    基于feign远程调用实际操作
    feign集成了ribbon,已经实现了负载均衡
    fegin集成了ribbon实现了负载均衡

    总结

    Feign的使用步骤:

    1. 引入依赖
    2. 添加@EnableFeignClients注解
    3. 编写FeignClient接口
    4. 使用FeignClient中定义的方法代替RestTemplate

    7.2 自定义feign配置

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

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

    一般我们需要配置的就是日志级别。
    配置Feign日志有两种方式:
    方式一:配置文件方式
    全局生效:

    feign:
    	client:
    		config:
    			default:  # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
    				loggerLeverl: FULL # 日志级别
    
    • 1
    • 2
    • 3
    • 4
    • 5

    局部生效:

    feign:
    	client:
    		config:
    			userservice: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
    				loggerLevel: FULL # 日志级别
    
    • 1
    • 2
    • 3
    • 4
    • 5

    方式二:java代码配置,需要先声明一个Bean

    public class FeignClientConfiguration{
    	@Bean
    	public Logger.Level feignLogLevel(){
    		return Logger.Level.BASIC;  // 引入的包: feign.Logger
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    而后,如果是全局配置,则把它放到@EnableFeignClients这个注解中:(加到启动类上)

    @EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class);
    
    • 1

    如果是局部配置,则把它放到@FeignClient这个注解中:(加到具体的client接口上)

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

    总结

    Feign的日志配置:

    1. 方式一是配置文件,feign.client.config.xxx,loggerLevel
    • 如果xxx是default则代表全局
    • 如果xxx是服务名称,例如userservice则代表某服务
    1. 方式二是java代码配置Logger.Level这个Bean
    • 如果是在@EnableFeignClients注解声明则代表全局
    • 如果在@EnableClient注解中声明则代表某服务

    7.3 Feign的性能优化

    7.3.1 Feign底层的客户端实现:

    • URLConnection:默认实现,不支持连接池
    • Apache HttpClient:支持连接池
    • OKHttp:支持连接池
      因为优化Feign的性能主要包括:
    • 使用连接池代替默认的URLConnection
    • 日志级别,最好用basic或none(默认none)

    7.3.2 Feign的性能优化–连接池配置

    Feign添加HttpClient的支持
    引入依赖:

    
    <dependency>
       <groupId>io.github.openfeigngroupId>
       <artifactId>feign-httpclientartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    配置连接池:

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

    真实业务中要对程序进行压测,来具体确定max-connections、max-connections-per-route的值

    总结:

    Feign的优化:

    1. 日志级别尽量使用basic
    2. 使用HttpClient和OKHttp代替URLConnection
      引入feign-httpClient依赖
      配置文件开启httpClient功能,设置连接池参数

    7.4 Feign最佳实践分析

    方式一(继承):

    给消费者的FeignClient和提供者的controller定义统一的父接口作为标准。
    feign最佳实践方式一
    一般我们不推荐客户端和服务端之间共享一个interface,因为会造成紧耦合,而且对spring mvc不起作用

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

    方式二(抽取):

    将FeignClient抽取为独立模块,并且把接口有关的POJO,默认的Feign配置都放到这个模块中,提供给所有的消费者使用
    feign最佳实践方式二
    降低了耦合度,但是如果order-service只用feign-api中的两三个接口,需要把feign-api的所有都加载出来。

    总结

    Feign的最佳实践

    1. 让controller和FeignClient继承同一接口
    2. 将FeignClient、POJO、Feign的默认配置都定义到一个项目中,供所有消费者使用

    7.5 实践:抽取FeignClient

    抽取FeignClient

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

    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

    方式二:指定FeignClient字节码(只拿UserClient)

    @EnableFeignClients(clients = {UserClient.clss})
    
    • 1

    总结

    不同包的FeignClient的导入有两种方式:

    1.在@EnableFeignClients注解中添加basePackages,指定FeignClient所在的包

    2.在@EnableFeignClients注解中添加clients,指定具体FeignClient的字节码

  • 相关阅读:
    【单片机毕业设计】【mcuclub-jj-025】基于单片机的台灯的设计
    PLSQL连接Oracle11g64位操作步骤
    计算机中的逻辑运算详解(与、或、非、同或、异或)
    Hive中UDFJar包被加载的时机
    什么牌子的运动耳机好用啊、运动耳机排行榜推荐
    RIP协议(路由信息协议)
    nginx负载均衡
    关于httpsrepo.maven.apache.orgmaven2报错 ERROR
    erlang开发环境搭建(Intellij IDEA)
    Liunx笔记-内核的组成概述
  • 原文地址:https://blog.csdn.net/Qing__zi/article/details/133638660