tulip notes
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Star-Lord

希望一天成为大师的学徒
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • SCAlibaba-Nacos

  • SCAlibaba-Sentinel

  • 负载均衡与服务调用

    • LoadBalancer的使用
    • OpenFeign的使用
      • 服务间的调用方式
        • 使用OpenFeign替代 RestTemplate
        • 硬编码问题
        • 声明式的服务间调用
      • 它的特点
        • 总结
      • 相关资料和文档
      • 快速上手
        • 上手步骤
      • 原理探究
        • 1. 动态代理
        • 2. 注解解析
        • 3. HTTP 请求构建和发送
        • 4. 响应处理
        • 总结
    • OpenFeign高级特性
  • 服务熔断与降级

  • 服务链路追踪与网关

  • 分布式实战与细节

  • 其他

  • 《SpringCloud》笔记
  • 负载均衡与服务调用
EffectTang
2024-11-02
目录

OpenFeign的使用

# OpenFeign的使用

# 服务间的调用方式

Spring Cloud中服务之间的调用方式主要有:

  1. Ribbon + RestTemplate:需要手动配置,负载均衡由Ribbon处理,比较灵活但代码较多。
  2. Feign:声明式接口,集成Ribbon和Hystrix,简化开发。
  3. OpenFeign:OpenFeign是Feign的一个升级版本,在Spring Cloud中被推荐使用以替代原Feign。继承了Feign的所有优点,并进行了增强。
  4. 异步消息(如RabbitMQ):通过消息队列解耦,适合异步处理。
  5. gRPC:Spring Cloud 并没有直接支持 gRPC,但可以通过社区维护的第三方库来集成,比如 grpc-spring-boot-starter,属于扩展方式。gRPC是由Google开发的一种高性能、开源的远程过程调用(RPC)框架。
  6. Spring Cloud Gateway:作为API网关,进行路由和过滤,可能用于外部请求的路由,但内部服务间调用可能还是用前几种。

每种方式都有其适用场景,选择时需根据具体需求考虑性能、易用性、扩展性等因素。

例如,对于简单的服务调用,RestTemplate或OpenFeign可能是较好的选择;而对于需要高性能和跨语言支持的场景,gRPC可能更为合适。Spring Cloud Gateway则通常用于构建微服务架构中的网关层,处理外部请求的分发和安全控制等任务。

# 使用OpenFeign替代 RestTemplate

在Spring Cloud环境中推荐使用OpenFeign替代RestTemplate的原因主要集中在以下几个方面:

  1. 声明式服务调用
  • 简化编码:OpenFeign通过注解的方式定义HTTP请求,使得开发者只需声明接口及方法即可实现远程服务的调用,而不需要手动构建HTTP请求。这种方式大大简化了代码编写过程。
  • 提高可读性:相比RestTemplate,OpenFeign的声明式编程模型让服务调用逻辑更加直观、易于理解。
  1. 自动集成Spring MVC注解:OpenFeign支持Spring MVC注解(如@RequestMapping, @GetMapping等),这使得从传统的Spring MVC控制器迁移到微服务客户端变得非常容易。

  2. 内置负载均衡:当与Spring Cloud Netflix Ribbon结合使用时(尽管Ribbon已经进入维护模式,但OpenFeign默认集成了负载均衡功能),OpenFeign可以自动利用Eureka提供的服务注册发现机制进行客户端负载均衡,无需额外配置。

  3. 强大的扩展能力:OpenFeign允许通过自定义配置类和拦截器来增强其功能,例如添加请求头、处理异常等,提供了高度的灵活性。

  4. 支持多种序列化格式:除了JSON,OpenFeign还支持其他数据格式(如XML)作为请求和响应的内容类型,增加了其适用范围。

  5. 减少样板代码:使用RestTemplate时,每次发起HTTP请求都需要创建模板实例并设置相应的参数,而在OpenFeign中,只需要定义一次接口,就可以重复使用这些定义,减少了大量的样板代码。

# 硬编码问题

有人说弃用RestTemplate的一个很大原因,是因为它的硬编码问题,其实不然,下面是它跟nacos进行服务间的调用。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class ConsumerController {

    private final RestTemplate restTemplate;

    @Autowired
    public ConsumerController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @GetMapping("/consumer")
    public String consumerService() {
        // 注意这里使用的是服务名,而非具体的IP和端口
        String result = restTemplate.getForObject("http://provider-service/provider", String.class);
        return "Consumer Service Call Result: " + result;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

在这个例子中,“provider-service”是注册到Nacos中的服务提供者的名字。RestTemplate会自动通过Nacos发现该服务的所有实例,并根据负载均衡策略选择一个实例进行调用。以上就一定程度上解决了该问题。

但为什么还要弃用它呢?

  1. 缺乏对复杂负载均衡策略的支持
  • 尽管Ribbon提供了基本的负载均衡策略(如轮询、随机等),但对于更复杂的负载均衡需求(例如基于响应时间、流量权重等的自定义策略),可能需要额外的工作来实现或集成第三方库。
  1. 错误处理与重试机制不足
  • 默认情况下,RestTemplate对于网络异常或服务不可达的情况处理较为简单。虽然可以通过添加拦截器等方式增强其错误处理能力和重试逻辑,但这增加了开发者的负担。
  • 对比之下,OpenFeign提供了更加灵活的错误处理机制(如通过实现ErrorDecoder接口),以及内置的重试功能,使得处理这类问题更为简便。
  1. 维护性和扩展性
  • 使用RestTemplate进行服务调用时,随着项目规模的增长,手动构建HTTP请求可能会变得冗长且难以维护。尤其是在需要处理多种不同的HTTP方法(GET、POST等)、不同格式的数据转换(JSON、XML等)时,代码量和复杂度都会显著增加。如果服务名很多且很长,那调用时,岂不是要传入很多,很长的参数。
  • OpenFeign通过声明式的方式简化了这些操作,减少了模板代码的数量,提高了代码的可读性和维护性。

能不能像我们去调用以前的一个逻辑方法一样,调用我们之前的一个业务方法一样,去调用我们的远程方法呢?比方说我去要用一个stock service点点什么点这个reduct方法,这样直接来请求我的远程方法,我们就可以直接来接收这个返回参数了,这样多简便,对不对?

Feign就实现了这个功能。

注意:

OpenFeign是声明在我们的这个服务消费端的,也就是在我们的客户端的。

不要把它声明在我们的这个服务提供方了。

# 声明式的服务间调用

使用SpringCloud LoadBalancer+RestTemplate时,利用RestTemplate对http请求的封装处理形成了一套模版化的调用方法。

但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,但这样的调用通常需要编写大量的样板代码,如构建 HTTP 请求、处理响应等。例如,使用 RestTemplate 手动构建请求和处理响应的代码可能非常冗长,而使用 OpenFeign 只需几行注解即可完成相同的功能。

// 传统方式
ResponseEntity<String> response = restTemplate.getForEntity("http://your-service-name/endpoint", String.class);
String result = response.getBody();
1
2
3

这样的调用数量上来后,会特别繁琐与麻烦。

为了解决这个问题,OpenFeign 出现了, 它通过声明式接口和注解,自动生成这些代码,大大减少了开发工作量。

在OpenFeign的实现下,我们只需创建一个接口并使用注解的方式来配置它(在一个微服务接口上面标注一个@FeignClient注解即可),即可完成对服务提供方的接口绑定,统一对外暴露可以被调用的接口方法,大大简化和降低了调用客户端的开发量,也即由服务提供者给出调用接口清单,消费者直接通过OpenFeign调用即可。

// OpenFeign 方式
@FeignClient(name = "your-service-name")
public interface YourServiceClient {
    @GetMapping("/endpoint")
    String callService();
}
1
2
3
4
5
6

# 它的特点

OpenFeign除了简化服务间的调用外,它还有以下几个优势:

集成服务发现和负载均衡:

  • 与 Spring Cloud 的服务发现组件和负载均衡组件无缝集成,自动处理服务发现和负载均衡。
  • 提高了系统的可维护性和灵活性。

断路器支持:

  • 与 Hystrix 集成,提供断路器功能,增强了系统的稳定性和容错能力。

可扩展性:

  • 支持自定义编码器、解码器、错误处理器等,满足不同业务场景的需求。

但,在使用OpenFeign的时候请注意——性能开销,这个问题。

  • 由于 OpenFeign 是基于注解和接口的动态代理实现,可能会引入一定的性能开销。
  • 在高并发场景下,需要注意性能调优。

# 总结

Spring Cloud OpenFeign 是一个强大的声明式 HTTP 客户端,它简化了微服务之间的调用,提供了服务发现、负载均衡和断路器等功能。通过简单的接口定义和注解,开发者可以更加专注于业务逻辑,而无需关心底层的 HTTP 请求细节。

# 相关资料和文档

SpringCloud OpenFeign官网:

# 快速上手

SpringCloud OpenFeign官网特性与使用说明 (opens new window)

  • https://docs.spring.io/spring-cloud-openfeign/reference/

SpringCloud OpenFeign官网首页介绍 (opens new window)

  • https://spring.io/projects/spring-cloud-openfeign#learn

# 上手步骤

注意,OpenFeign,需要跟 服务注册组件一起使用,比如consul或者nacos等。

第一步:引入对应pom坐标,官网的对应说明如下:

To include Feign in your project use the starter with group org.springframework.cloud and artifact id spring-cloud-starter-openfeign.

 <!--openfeign-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
  </dependency>
	<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  </dependency>
1
2
3
4
5
6
7
8
9

从Spring Cloud 2020.0.0版本开始,Ribbon(之前用于负载均衡的默认工具)被Spring Cloud LoadBalancer取代。

因此,如果你遇到了"No Feign Client for loadBalancing defined"这样的错误提示,很可能是由于缺少spring-cloud-starter-loadbalancer依赖或未正确启用Spring Cloud LoadBalancer。

同时,你还要注意的是,这个OpenFeign,它是属于spring cloud,所以你要先确定一下有添加spring load的版本管理器。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2021.0.5</version> <!-- 根据需要选择合适的版本 -->
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
1
2
3
4
5
6
7
8
9
10
11

注意:OpenFeign是在消费端进行使用。

第二步:修改配置文件,让服务注册中心

server:
  port: 80
 
spring:
  application:
    name: cloud-consumer-openfeign-order
  ####Spring Cloud Consul for Service Discovery
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        prefer-ip-address: true #优先使用服务ip进行注册
        service-name: ${spring.application.name}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

第三步:在主类或配置类中添加注解@EnableFeignClients(需要开放接口给其他服务调用的微服务),开启OpenFeign,启用服务间的发现。

@SpringBootApplication
@EnableFeignClients
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}
1
2
3
4
5
6
7
8
9

第四步:将之前的接口进行抽象添加注解,这些接口可以单独放在一个module中,也可以就在原有module中。这一步也成为定义Feign客户端。

// 定义 Feign 客户端
@FeignClient(name = "your-service-name")
//@FeignClient(name = "order" ,path = "/controller-path")
public interface YourServiceClient {
    @GetMapping("/endpoint")
    String callService();
}
1
2
3
4
5
6
7

your-service-name,就是你注册到服务中心的微服务名称,下方的接口callService(),就是your-service-name-微服务中对应的接口,请注意接口对应的返回值也要一致。如果controller类上有mapping路径,则需要加上属性 path,值则为 controller-path。

到此,OpenFeign实现服务间的调用全部完成。

OpenFeign,它的这种远程调用的方式,它会自动的帮我们去集成ribbon,帮我们去集成负载均衡器.

同样的会去帮我们集成我们的nacos。根据我们在接口,注解上,写的这个服务名,去我们nacos当中获取对应的所有的服务实例。再结合我们的这个负载均衡器来进行调用,使用了动态代理。这些是基本的原理。

在需要的服务中注入并使用 Feign 客户端,即可调用其他微服务接口。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class YourService {

    @Autowired
    private UserServiceClient userServiceClient;

    public User getUserById(Long id) {
        return userServiceClient.getUser(id);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

最后提示,为了更好的使用,可以将以上第四步中的接口,放到一个公共module中,从而达到更高效的利用率。

# 原理探究

OpenFeign 的实现原理主要包括以下几个方面:

  • 动态代理
  • 注解解析
  • HTTP 请求构建和发送
  • 以及响应处理。

先大致说下流程:

首先是要通过咱们启动类上的@EnableFeignClients这个注解,开启对Feign接口代理对象的构建以及装配。在注解源码中咱们可以看到它导入了一个叫做FeignClientsregister的注解。这个注解会扫描添加了`@FeignClientd注解的接口,并且创建远程调用的代理对象。而且还会将这个对象注入到咱们的spring容器中。这样我们就可以在需要的位置直接注入rpc远程调用的代理对象。

而在构建代理对象时,会为每一个远程调用的方法生成一个 requestTemplate 的请求模板实例。内部存储了整个请求的路径,请求方式以及请求参数等等。在发生请求调用时,会基于咱们的 requestTemplate 生成一个request的实例。在做具体请求发送前,需要基于FeignClient 的客户端的负载均衡实例去选择合适的服务。那一般会采用ribbon或者是咱们的load baLance,再基于成员变量client的对象的delegate去完成HTTP的请求的提交。而delay gate类型一般咱们会采用Apache 提供的HTTP client去完成远程调用。

# 1. 动态代理

OpenFeign 使用 Java 的动态代理机制来生成接口的实现类。当开发者定义了一个带有 @FeignClient 注解的接口时,OpenFeign 会为这个接口生成一个代理类。这个代理类负责处理实际的 HTTP 请求和响应。

# 2. 注解解析

OpenFeign 通过解析接口上的注解来确定 HTTP 请求的详细信息,包括请求方法、URL、请求参数等。常用的注解包括:

  • @GetMapping、@PostMapping、@PutMapping、@DeleteMapping 等,用于指定 HTTP 方法。
  • @PathVariable、@RequestParam、@RequestBody 等,用于指定请求参数的来源和格式。

# 3. HTTP 请求构建和发送

OpenFeign 使用 HttpClient、OkHttp 或 Ribbon 等 HTTP 客户端库来构建和发送 HTTP 请求。具体步骤如下:

  1. 解析注解:根据接口上的注解解析出请求方法、URL、请求参数等信息。
  2. 构建请求:使用解析出的信息构建 HTTP 请求。
  3. 发送请求:通过配置的 HTTP 客户端发送请求。

# 4. 响应处理

OpenFeign 处理 HTTP 响应并将结果转换为接口方法的返回类型。具体步骤如下:

  1. 接收响应:从 HTTP 客户端接收响应。
  2. 解析响应:将响应体解析为指定的返回类型。
  3. 返回结果:将解析后的结果返回给调用者。

# 总结

其他服务调用这些接口,先去OpenFeign中找,OpenFeign通过代理进行请求,得到结果后,返回给调用者。是不是有拦截器那味了。

上次更新: 2025/04/23, 16:23:16
LoadBalancer的使用
OpenFeign高级特性

← LoadBalancer的使用 OpenFeign高级特性→

最近更新
01
面向切面跟自定义注解的结合
05-22
02
时间跟其他数据的序列化
05-19
03
数据加密与安全
05-17
更多文章>
Theme by Vdoing | Copyright © 2023-2025 EffectTang
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式