Feign-基于Feign远程调用(八)

发布时间 2024-01-10 14:17:04作者: DAYTOY-105

1 Feign 替代 RestTemplate

RestTemplate 方式调用存在的问题

使用RestTemplate发起远程调用的代码:

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

存在下面的问题:

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

2 Feign的介绍

Feign是一个声明式的http客户端,官方地址:http://github.com/OpenFeign/feign

其作用就是帮助我们优雅的实现http请求的发送,解决上述问题。

3 定义和使用Feign客户端

使用Feign的步骤如下:

  1. 引入依赖

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

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

@EnableFeignClients
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
   public static void main(String[] args){
      SpringApplication.run(OrderApplication.class,args);  
   }          
}

 使用Feign的步骤如下:

  3.编写Feign客户端

@FeignClient("userservice")
public interface UserClient {
  @GetMapping("/user/{id}")
  User findById(@PathVariable("id") Long id);
}

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

  • 服务名称:userservice
  • 请求方式:GET
  • 请求路径:/user/{id}
  • 请求参数:Long id
  • 返回值类型:User

  4.使用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;
}

总:

Feign的使用步骤:

  • 引入依赖;
  • 添加@EnableFeignClients注解;
  • 编写FeignClient接口;
  • 使用FeignClient中定义的方法代替RestTemplate

4 自定义Feign的配置

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

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

一般我们需要配置的就是日志级别。

  2. 配置Feign日志的两种方式:

方式一:配置文件方式

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

方式二:java代码的方式

  • 需要先声明一个Bean:
public class FeignClientCongiguration {
  @Bean
  public Logger.Level.feignLogLevel(){
    return  Logger.Level.BASIC;
  }
}
  • 而后如果是全局配置,则把它放到@EnableFeignClients这个注解中:
@EnableFeignClient(defaultConfiguration = FeignClientConfiguration.class)
  • 如果是局部配置,则把它放到@FeignClient这个注解中:
@FeignClient(value = "userservice",configuration = FeignClientConfiguration.class)

5 Feign的性能优化

Feign底层的客户端实现:

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

因此优化Feign的性能主要包括:

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

总:

Feign的优化:

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

6 Feign的最佳实践

方式一(继承):给消费者的FeignClient和提供者的controller定义统一的父接口作为标准;

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

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

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

  • 在@EnableFeignClients注解中添加basePackages,指定FeignClient所在的包;
  • 在@EnableFeignClients注解中添加clients,指定具体FeignClient的字节码。