Http Client - OpenFeign 入门

本文探讨了在Spring Cloud中,从使用RestTemplate进行服务调用到采用OpenFeign的转变。RestTemplate虽然能完成HTTP请求,但在代码可读性、优雅性和复杂URL维护上存在问题。而OpenFeign提供了一种声明式的方法,通过定义接口简化了服务间的调用,使得代码更加简洁和易于维护。同时,OpenFeign内置了负载均衡器,并支持自定义配置,如日志级别调整和性能优化。通过启用FeignClients和配置连接池,可以进一步提升系统的性能和可读性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

RestTemplate 里的一些问题

RestTemplate 是1个经典的java http 客户端
黎睇睇常见的http call 代码

  @Autowired
  private RestTemplate restTemplate;

  private String user_service = "demo-cloud-user-service";

  public Order queryOrderById(Long orderId) {
        // 1.get order object
        Order order = orderMapper.findById(orderId);

        //2 use user service to get the user details
        String url = "http://" + user_service.toUpperCase(Locale.ROOT) + "/user/" + order.getUserId();
        System.out.println("url:" + url);

        User user = restTemplate.getForObject(url, User.class); // User.class means return format
        order.setUser(user);

        return order;
    }

可以见到, 即使我们使用了Eureka注册中心, 不用hardcode hostname到url中, 而是使用service name代替,但是还是存在如下的问题

1. 代码可读性不好

对于下面这一行, 没接触过RestTemplate 的开发人员不容易理解

 User user = restTemplate.getForObject(url, User.class); // User.class means return format
2. 感觉在写前端,不够优雅

出现了url 代码的风格乱了, 总想封装它

3. 复杂的url 难以维护

上面的url例子只有1个参数, 已经是拼接到一定程度了

Spring Cloud Fegin的介绍

OpenFeign是1个声明式客户端
https://spring.io/projects/spring-cloud-openfeign

官方介绍:
Feign is a Java to HTTP client binder inspired by Retrofit, JAXRS-2.0, and WebSocket. Feign’s first goal was reducing the complexity of binding Denominator uniformly to HTTP APIs regardless of ReSTfulness.

Feign的基本客户端代码:
定义1个User service 的Client 接口

@FeignClient("demo-cloud-user-service")
public interface UserServiceClient {
	@GetMapping("/user/{id}")
	User findbyId(@PathVariable("id") long id)}

其中包含了:
service name: demo-cloud-user-service
Request type: Get
Request url: /usr/{id}
Request parameter: Long id
Return format: User

使用Feign的客户端代码:

  @Autowired
  private UserServiceClient userServiceClient;
  
  public Order queryOrderById(Long orderId) {
        // 1.get order object
        Order order = orderMapper.findById(orderId);

        //2 use user service client to get the user details
        User user = userServiceClient.findByid(order.getUserId());
        order.setUser(user);

        return order;
    }

是不是很简洁优雅, 定义interface 的写法就像是写controller
使用的客户端的代码就像是简单调用另1个service 函数

OpenFeign 内部已经继承Ribbon, 默认就已经开启LoadBalancer

添加Pom.xml 依赖

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

可以知道openfeign 也是spring cloud的组件

开启feign 自动装配

在启动类上加上 注解@EnableFeignClients

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

编写Feign Client 接口

@FeignClient("demo-cloud-user-service")
public interface UserClient {
    
    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") long id);
}

在Order Service 里使用 上面的都接口实现 http调用

    @Autowired
    private UserClient userClient;

    //new method to use OpenFeign
    public Order queryOrderById(Long orderId) {
        // 1.get order object
        Order order = orderMapper.findById(orderId);

        //2 use user service to get the user details
        User user = userClient.findById(order.getUserId());
        order.setUser(user);

        return order;
    }




OpenFeign 的一些自定义配置

可以编写一些自定义配置来覆盖默认配置, 包括且不限于:

Itemdescremark
feing.logger.levelupdate logs levelincluds: NONE/BASIC/HEADERS/FULL
feing.codec.Decoderparse of return resultincluds: e.g translate json -> java objs
feing.codec.EncoderEncoder of request parametersEncode request parameters for transition
fegn.Contractformat of annotationFor default, use Spring MVC’s annotation
feign.RetryerFailure retry mechanismFor Default: None, but we could use the built-in Ribbon

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

如何修改日志级别

https://www.baeldung.com/java-feign-logging

方法一,修改项目配置文件

feign.client.config.default.loggerLevel= basic # default means global setting, for all the services

default 代表全局配置

feign.client.config.demo-cloud-user-service.loggerLevel= full # for specified service 

单独为某1个微服务服务配置日志级别

方法二:在Java里配置

首先创建1个配置类, 里面必须有个bean for 日志level

import feign.Logger.Level;
import org.springframework.context.annotation.Bean;

public class FeignClientConfiguration {
    @Bean
    public Level feignLogLevel(){
        return Level.BASIC;
    }
}

如果想全局生效
放入启动类的注解里

@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)

如果想在单独service里生效 放在对应的FeignClient的注解里

@FeignClient(value = "demo-cloud-user-service", configuration = FeignClientConfiguration.class)

亲测 方法一会覆盖方法二

注意, feign的日志要开启 debug level 才有考, 如果全局开debug level会令到可读性下降, 所以一般用下面配置只令到 项目的类开启debug level
如:

logging:
  level:
    com.home.api: DEBUG




Feign 的性能优化

3种实现模式

itemdesc
URLConnection默认,jdk 自带, 不支持connection Pool
Apache HttpClient默认, 支持connection Pool
OKHttp默认, 支持connection Pool

因此,我们通常会使用连接池替代默认的URLConnection

第一步, 引入 feign-httpclient 依赖
      <!-- http client for Feign -->
         <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>

注意 版本已被spring 管理, 不需要指定版本号

第二步, 在springboot配置文件配置连接池

feign:
  httpclient:
    enabled: true
    max-connections: 200 # for all
    max-connections-per-route: 50 # for each url

如何验证,我从日志中真的看不出来连接池有没有开启。。。

但系中debug中的确可以见到, 但是要进入到 feign-core 这个包

在这里插入图片描述

上面两个测试通常要做压力测试才能确定最佳值
如果真的追求性能, 建议日志基本也降为Null or basic

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nvd11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值