当前位置: 首页 > article >正文

揭秘 Feign 调用机制:微服务通信的无缝集成

在微服务架构中,服务之间的通信是核心中的核心。之前的文章Spring Boot 项目高效 HTTP 通信:常用客户端大比拼!介绍了基于SpringBoot的项目开发中常用的Http客户端,并分析了RestTemplate和Okhttp3的关于源码,详见深入 Spring RestTemplate 源码:掌握 HTTP 通信核心技术和揭开 OkHttp3 高效处理 HTTP 请求的神秘面纱:池技术与拦截器。
今天我们将在此基础上,继续探究Feign的调用机制。了解它是如何在无需指定域名的情况下,找到并调用微服务的。

一、什么是Feign

Feign 是一个声明式的 Web 服务客户端。它通过注解的方式,将接口方法映射为 HTTP 请求,极大简化了微服务之间的通信。Feign 的设计灵感来源于 Retrofit、JAX-RS 和 WebSocket,在 Spring Cloud 生态中扮演着重要角色,广泛应用于微服务间通信。

二、Feign快速上手

1. 导入maven依赖

首先,在项目的 pom.xml 中添加以下依赖,以便使用 Spring Cloud OpenFeign。

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

2. 定义Feign的client

@FeignClient(value = "customer-api")
public interface CustomerFeign {
	@GetMapping(value = "customer/get-customer-info")
    Response<EmployeeVo> getCustomerInfo(@RequestParam("customerId") String customerId);
}

通过 @FeignClient 注解,声明了一个名为 CustomerFeign 的接口,该接口将作为与customer-api微服务通信的客户端。
value 属性指定了目标微服务的名称,Feign客户端会根据这个名称在服务注册与发现组件(如Eureka)中查找并调用相应的服务。
关于Eureka的使用及原理见Eureka系列。

3. 启动Feign客户端

在 Spring Boot 应用的启动类中,添加 @EnableFeignClients 注解以启用 Feign 客户端功能。

@Slf4j
@EnableFeignClients 
@EnableAspectJAutoProxy(exposeProxy = true)
@SpringCloudApplication
@EnableApolloConfig
public class Main {
	……
}

关于这个注解以及@FeignClient的实现细节,后面有时间了会出一篇博客专门来讲)。

三、Feign为什么不需要域名?

Feign 的强大之处在于它不需要具体的域名即可找到服务。其背后依赖于 Ribbon 和 Eureka 的集成。
Feign 通过与 Ribbon 和 Eureka 的无缝集成,实现了动态服务发现和负载均衡。核心方法如下:

  1. cleanUrl(String originalUrl, String host)方法
	static URI cleanUrl(String originalUrl, String host) {
		String newUrl = originalUrl;
		// 规范化 URL 并去掉主机信息
		if (originalUrl.startsWith("https://")) {
			newUrl = originalUrl.substring(0, 8)
					+ originalUrl.substring(8 + host.length());
		}
		else if (originalUrl.startsWith("http")) {
			newUrl = originalUrl.substring(0, 7)
					+ originalUrl.substring(7 + host.length());
		}
		StringBuffer buffer = new StringBuffer(newUrl);
		if ((newUrl.startsWith("https://") && newUrl.length() == 8)
				|| (newUrl.startsWith("http://") && newUrl.length() == 7)) {
			buffer.append("/");
		}
		return URI.create(buffer.toString());
	}

cleanUrl 方法负责去掉 URL 中的域名部分,以服务名称代替。例如 http://customer-api或者https://customer-api。
2. execute(Request request, Request.Options options)方法

	public Response execute(Request request, Request.Options options) throws IOException {
		try {
			// 构建请求
			URI asUri = URI.create(request.url());
			String clientName = asUri.getHost();
			// 清除域名
			URI uriWithoutHost = cleanUrl(request.url(), clientName);
			FeignLoadBalancer.RibbonRequest ribbonRequest = new FeignLoadBalancer.RibbonRequest(
					this.delegate, request, uriWithoutHost);
            // 选择合适的实例
			IClientConfig requestConfig = getClientConfig(options, clientName);
			// 发送请求
			return lbClient(clientName)
					.executeWithLoadBalancer(ribbonRequest, requestConfig).toResponse();
		}
		catch (ClientException e) {
			IOException io = findIOException(e);
			if (io != null) {
				throw io;
			}
			throw new RuntimeException(e);
		}
	}

在 execute 方法中,Feign 通过服务名称找到对应的服务实例,并利用 Ribbon 的负载均衡策略进行调用。

private FeignLoadBalancer lbClient(String clientName) {
		return this.lbClientFactory.create(clientName);
	}

服务实例列表的获取,负载均衡策略的选择,表面看是封装在了executeWithLoadBalancer方法中,实则隐含在 Ribbon 的底层处理逻辑中(下节探讨)。

四、总结

Feign 在 Spring Cloud 生态中,提供了高效、优雅的 HTTP 请求方式,其通过与 Ribbon 的深度集成,实现了灵活的服务调用,无需域名即可动态寻找并访问目标服务,大大简化了微服务环境中的服务间通信配置。

下一篇文章,我们将深入探讨Ribbon是如何获取服务实例列表并执行负载均衡相关策略选择具体服务实例的。敬请期待!


http://www.kler.cn/news/361028.html

相关文章:

  • 信创服务器下搭建nfs共享存储方案
  • spring源码拓展点3之addBeanPostProcesser
  • MIT6.S081 LAB page tables (2024)
  • C++ 游戏开发:从基础到进阶
  • 2025秋招八股文--网络原理篇
  • React 基础阶段学习计划
  • 点云数据介绍
  • [论文笔记]RA-DIT: RETRIEVAL-AUGMENTED DUAL INSTRUCTION TUNING
  • Golang | Leetcode Golang题解之第497题非重叠矩形中的随机点
  • Python程序设计 内置函数 日志模块
  • eIQ笔记(UI介绍+Loss曲线+OpenART例程)
  • linux更改系统时间
  • 基于基于MATLAB红外和可见光图像融合算法研究
  • 【分布式微服务云原生】《微服务架构下的服务治理探秘》
  • 从外行人的角度解释1Bit的模型,是怎样改变世界的
  • Qt编写的modbus模拟器/支持网络和串口以及websocket/支持网络rtu
  • Standard_Matrix
  • 异步优化看板查询接口,从29s优化至2.8s
  • 如何自定义一个自己的 Spring Boot Starter 组件(从入门到实践)
  • Tcp协议讲解与守护进程