SpringCloud 之 Feign的最佳实践

862 阅读3分钟

http 客户端 Feign

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情

RestTemplate方式调用存在的问题

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

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

存在的问题:

1.代码可读性比较差

2.编程体验统一

3.参数复杂的URL难以维护

下面我们来实战feign

http客户端Feign(快速入门)

1.引入依赖(openfeign)

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

2.在clients包下创建UserClient

记得加上注解FeignClient

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

指定要请求的服务,这个等价于最上面书写的RestTemplate方式

3.在Impl里面去调用

    @Autowired
    private UserClient UserClient;
    public Order queryOrderById(Long orderId) {
        Order order = orderMapper.findById(orderId);
        User user = UserClient.findById(order.getUserId());
        order.setUser(user);
        return order;
    }

4.在启动类中加入@EnableFeignClients注解

image-20221008180555640.png

注意:

我们点进feign的依赖包发现 ,里面已经自动集成了ribbon,因此我们无需再去配置负载均衡,feign已经帮我们做好了

image-20221008180632035.png

自定义feign的配置

我们可以通过覆盖feign默认的配置,来自定义

image-20221008181133548.png

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

有两种方式

1.property文件

例如,我们在orderservice里面写

# 全局配置
feign:
  client:
    config:
      default:
        loggerLevel: FULL
# 局部配置
feign:
  client:
    config:
      userservice:
        loggerLevel: FULL

这个时候的日志,会打印出user的接口的调用和响应,总之日志会更加全面

2.Bean配置

没那必要,不写了

Feign性能优化

Feign底层的客户端实现:

1.URL connection:默认实现,不支持连接池

这个不推荐,因为不支持连接池,你想想看,每次请求很多次握手,挥手,性能浪费的厉害

2.Apache HttpClient:支持连接池

3.OkHttp:支持连接池

因此,Feign的性能优化有两点

1.使用连接池代替默认的URLConnection

2.日志级别,最好用basic或者none,full其实挺占用内存的,嗯

Feign性能优化-连接池的配置

1.引入httpClient依赖

       <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>

2.配置文件里面改个连接方式

feign:
  client:
    config:
      default:
        loggerLevel: Basic
  httpclient:
    enabled: true
    max-connections: 200
    max-connections-per-route: 50

max-connection是指最大连接数, max-connections-per-route是单个请求的最大连接数,这些就是连接池的配置了

Feign的最佳实践--理论

什么是最佳实践?不过是踩坑后的最好解决办法罢了

核心思想就是:抽取

思考一个场景,如果有1000个微服务,同时想要调用userservice,那么是不是每一个微服务,都需要去写一个userClient?

image-20221008184908853.png

那么,毫无疑问,这是很烦人的,一俩个倒还行,多了就麻烦了。

为了解决这样的问题,我们需要将这个东西进行抽取,将FeignClient抽取为一个独立的模块,并且把相关的pojo类(这里是User),默认的feign配置放入其中,提供给所有消费者使用,那么这时,别的服务引入一个依赖即可

image-20221008185126761.png

Feign的最佳实践--实现

1.新建一个新的模块 我们就叫它 feign-api-1吧(纯属自己起的名)

2.引入feign客户端依赖

<dependencies>
        <!--        feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--        改良feign的连接方式改成httpClient-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
    </dependencies>

再加个版本吧,方便其它模块进行导入

image-20221009223252515.png

这里是3.0版本,因为我踩了很多坑,改了很多次,才成这样!

3.将UserClient copy过来

image-20221009223420308.png

记住,这里的方法名,参数名,还有路径一定要和User模块里面的东西一模一样!!

然后不要忘记写name,如果别人请求userservice,那么会这么请求http://userservice/user/1

4.之前用于配置feign的logs配置文件也要粘过来

public class DefaultFeignConfiguration {
    @Bean
    public Logger.Level logLevel(){
        return Logger.Level.FULL;
    }
}

然后在orderService不要忘记配置

@EnableFeignClients(clients = {UserClient.class},defaultConfiguration = DefaultFeignConfiguration.class)

这里指定了feign的UserClient,然后制定logs的配置类,

5.然后引入即可