# old 调用方式劣势?

以前写的 RestTemplate 调用有什么劣势?

public Order queryOrderById(Long orderId) {
        // 1. 查询订单
        Order order = orderMapper.findById(orderId);
        // 2. 利用 RestTemplate 发送 http 请求,查询用户信息
        // 2.1 设置 url 地址
        String url = "http://userservice/user/"+ order.getUserId();
        // 2.2 发送 Http 请求,实现远程调用
        User user = restTemplate.getForObject(url, User.class);
        // 2.3 封装 user 到 Order 中
        order.setUser(user);
        // 4. 返回
        return order;
    }

存在下面的问题:

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

所以,我们使用一种 http 客户端 FeginFeign 是一个声明式的 http 客户端,其作用就是帮助我们优雅的实现 http 请求的发送.

# Feign 的使用步骤

# 引入依赖

<!-- 配置 feign 的客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

# 添加 @EnableFeignClients 注解(开关)

image.png 注意:在主类上开启 EnableFeignClients 注解,那么我们的程序将会自动扫描 clsspath 下面所有被 Feignclient 注解类,(value 值为服务名称)打上该注解的 bean(一般是接口,生成代理类当成 bean), 会注入到 spring 的 ioc 容器中,最后通过处理器一系列复杂的操作,最后给我们的服务端发送一个 http 的请求。

# 编写 FeignClient 接口

例如:

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

# 使用 FeignClient 中定义的方法代替 RestTemplate

@Autowired
private UserClient userClient; // 注入
public Order queryOrderById(Long orderId) {
        // 1. 查询订单
        Order order = orderMapper.findById(orderId);
        User user = userClient.findUser(order.getUserId());    //  调用即可
        // 2.3 封装 user 到 Order 中
        order.setUser(user);
        // 4. 返回
        return order;
    }

正常的注入后,调用接口中的方法即可。

# 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 的重试

** 我们可配置日志等级:**** 例如:** 全局生效:

feign:
  client:
    config:
      default:  # 这里用 default 就是全局配置,如果是写服务名称,则是针对某个微服务的配置
        logger-level: full  # 配置为 FULL 格式的

局部生效:

feign:
  client:
    config:
       userservice: # 这里用 default 就是全局配置,如果是写服务名称,则是针对某个微服务的配置
        logger-level: full  # 配置为 FULL 格式的

FULL 格式:image.pngjava 代码的方式配置:首先创建一个配置类,来创建 bean;

public class FeignClientConfig {
    @Bean
    public Logger.Level feignLog(){
        return Logger.Level.BASIC;
    }
}

然后,在开启注解上声明当前为类为配置类,这样好管理一些:默认配置:

@EnableFeignClients(defaultConfiguration = FeignClientConfig.class)

指定服务配置:

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

# 总结一下:

Feign 的日志配置:1、 方式一是配置文件,

  • feign.client.config.xxx.loggerLevel
    • 如果 xxx 是 default 则代表全局
    • 如果 xxx 是服务名称,例如 userservice 则代表某服务

2、方式二是 java 代码配置 Logger.Level 这个 Bean

  • 如果在 @EnableFeignClients 注解声明则代表全局
  • 如果在 @FeignClient 注解中声明则代表某服务

注意:如果我们每次请求都是新建一个连接,这样访问速度是不是会很慢,如果我们可以使用像 durid 连接池那样,连接宿舍是不是会很快。Feign 底层的客户端实现:

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

# 如何使用连接池呢?

引入依赖:

<!--httpClient 的依赖 -->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
         </dependency>

配置连接池:

# feign 连接至配置
feign:
  client:
    config:
      default:
        logger-level: full
  httpclient:
    enabled: true  # 开启 feign 对 HttpClient 的支持
    max-connections: 200  # 最大的连接数
    max-connections-per-route: 50  # 每个路径的最大连接数

# Feign 的优化:

1、日志级别尽量用 basic2、使用 HttpClient 或 OKHttp 代替 URLConnection

  • 引入 feign-httpClient 依赖配置文件
  • 开启 httpClient 功能,设置连接池参数

# Feign 的最佳实战(我感觉这样好一些):

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