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

深度解析 Feign

一、引言

在当今微服务架构盛行的时代,众多微服务相互协作构成了复杂的分布式系统。然而,各个微服务之间的调用往往涉及到诸多繁琐的细节,比如网络请求的构建、参数的处理、响应的解析等。为了让开发人员能够更加专注于业务逻辑的实现,而无需深陷于这些底层的通信细节中,Feign 应运而生。它就像是一座桥梁,巧妙地连接起各个微服务,使得服务间的调用变得简洁高效。接下来,我们将深入探究 Feign 究竟是什么,以及它所具备的诸多优点,帮助大家更好地理解并运用这一强大的工具。

二、Feign 的概述

(一)Feign 的定义

Feign 是一个声明式的 HTTP 客户端,它由 Netflix 开源,并在 Spring Cloud 微服务框架中得到了广泛的应用。简单来说,它允许开发人员使用简单的注解和接口定义的方式,去轻松地实现对其他微服务的 HTTP 接口调用,仿佛调用本地的方法一样自然流畅,极大地简化了微服务之间的通信过程。

例如,在一个电商系统中,订单微服务可能需要调用商品微服务来获取商品的详细信息,使用 Feign,开发人员只需定义一个接口,在接口上添加相应的 Feign 注解,就能便捷地发起对商品微服务的 HTTP 请求,获取所需的数据,而不用像传统方式那样手动去构建 URL、设置请求头、处理请求参数以及解析返回的 JSON 或其他格式的响应数据等复杂操作。

(二)Feign 的历史与发展

Feign 最初诞生于 Netflix,旨在解决其内部众多微服务之间相互调用的难题。随着微服务架构在业界的广泛认可和应用,Feign 凭借其简洁易用的特性,逐渐受到了越来越多开发者的关注。后来,它被集成到 Spring Cloud 生态系统中,与 Spring Cloud 中的其他组件(如服务注册与发现组件、熔断器组件等)进行了深度整合,进一步完善了其功能,成为了 Spring Cloud 微服务开发中进行服务间调用的热门选择。

三、Feign 的工作原理

(一)接口定义与注解使用

  1. 接口声明
    Feign 通过让开发人员定义接口来描述对远程服务的调用逻辑。以调用用户微服务获取用户信息为例,我们可以这样定义接口:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "user-service")
public interface UserServiceClient {@GetMapping("/users/{id}")User getUserById(@PathVariable("id") String id);
}

在上述代码中,首先使用 @FeignClient 注解标记这个接口,表示它是一个 Feign 客户端,用于与名为 "user-service" 的远程服务进行交互。这里的 "user-service" 通常对应着服务注册与发现中心(如 Eureka、Nacos 等)中注册的服务名称,通过这样的命名关联,Feign 能够借助服务注册与发现机制找到对应的服务实例所在的地址。

然后,在接口中定义了 getUserById 方法,这个方法对应着远程用户微服务提供的获取用户信息的 HTTP GET 请求接口。通过 @GetMapping 注解指定了请求的路径,其中 {id} 表示路径中的参数占位符,并且使用 @PathVariable("id") 注解将方法的参数 id 与路径中的参数进行绑定,使得在实际调用时,会将传递进来的 id 值替换到请求路径中相应的位置,就如同在本地定义了一个获取用户信息的普通方法一样,但其实际执行会发起对远程服务的 HTTP 请求。

  1. 注解解析与请求构建
    当在代码中调用这个定义好的 Feign 接口方法时,Feign 框架会自动解析接口上的各种注解(如 @GetMapping@PostMapping@RequestParam 等不同的 HTTP 请求方法对应的注解以及参数绑定注解),根据注解信息来构建出完整的 HTTP 请求。它会确定请求的 URL(结合服务名称、接口定义的路径以及参数等信息)、请求方法(GET、POST 等)、请求参数(如果有)等内容,然后通过底层的 HTTP 客户端(默认通常是基于 java.net.HttpURLConnection,也可以配置为其他如 Apache HttpClient 或 OkHttpClient 等)将请求发送出去。

例如,在某个业务逻辑代码中,我们可以这样使用上面定义的 UserServiceClient 接口:

import org.springframework.stereotype.Service;@Service
public class OrderService {private final UserServiceClient userServiceClient;public OrderService(UserServiceClient userServiceClient) {this.userServiceClient = userServiceClient;}public void processOrder(String userId) {User user = userServiceClient.getUserById(userId);// 基于获取到的用户信息进行订单相关处理,比如验证用户权限、记录用户下单信息等System.out.println("获取到用户信息: " + user);}
}

在 OrderService 类的 processOrder 方法中,当调用 userServiceClient.getUserById(userId) 时,Feign 就会按照之前接口定义时的注解信息构建一个类似 GET http://user-service/users/{具体的用户ID} 的 HTTP 请求,并发送出去,去获取对应的用户信息,之后返回的结果会被自动解析并转换为 User 类型(假设 User 是对应的实体类),供后续业务逻辑使用。

(二)服务注册与发现集成

  1. 与注册中心配合
    Feign 自身能够很好地与常见的服务注册与发现组件协同工作,如 Eureka、Nacos、Zookeeper 等。以 Eureka 为例,在一个 Spring Cloud 微服务项目中,各个微服务都会将自己的服务信息(包括服务名称、实例地址、端口等)注册到 Eureka 服务注册与发现中心上。

当 Feign 客户端发起对某个服务的调用时(如前面定义的 UserServiceClient 对 "user-service" 的调用),它会先向 Eureka 服务器查询 "user-service" 对应的可用服务实例列表,然后根据一定的负载均衡策略(Spring Cloud 中通常默认使用 Ribbon 进行负载均衡,后面会详细介绍其与 Feign 的配合)从这些实例中选择一个来发送 HTTP 请求。这样,即使某个服务实例出现故障或者下线,Feign 依然能够通过服务注册与发现机制找到其他可用的实例进行调用,保障了服务间调用的可靠性和高可用性。

例如,假设 user-service 在 Eureka 上注册了多个实例,分别运行在不同的服务器上,Feign 在发起请求时,会借助 Ribbon 的轮询策略(如果采用默认配置)依次选择不同的实例来发送请求,使得请求能够均匀地分布到各个可用实例上,避免某个实例负载过重,同时提高了整个系统应对单个实例故障的能力。

  1. 动态服务地址获取
    由于微服务的实例地址可能会因为部署环境的变化、服务器的扩容或缩容等原因而动态改变,Feign 借助服务注册与发现的动态特性,能够实时获取最新的服务实例地址,而无需开发人员手动去更新调用的 URL 等信息。这就好比在一个城市中,各个商店(微服务实例)可能会搬家或者新开分店(新增实例),但作为顾客(Feign 客户端),只要通过一个统一的服务台(服务注册与发现中心)就能随时找到想去的商店的最新地址,进行购物(服务调用),大大降低了服务调用的维护成本,使得微服务架构在面对复杂的部署和运维场景时依然能够灵活应对。

(三)负载均衡机制

  1. 与 Ribbon 的关联
    在 Spring Cloud 中,Feign 默认集成了 Ribbon 来实现负载均衡功能。Ribbon 是一个客户端负载均衡器,它提供了多种负载均衡策略,如轮询(RoundRobin)、随机(Random)、加权响应时间(WeightedResponseTime)等。

当 Feign 发起对某个服务的调用时,Ribbon 会从该服务对应的多个实例中,根据配置的负载均衡策略选择一个合适的实例来发送 HTTP 请求。例如,在前面提到的 UserServiceClient 调用 user-service 的场景中,如果采用轮询策略,Ribbon 会依次将请求分配到 user-service 的各个可用实例上,保证每个实例都能均匀地处理请求,避免出现某个实例长时间空闲而另一个实例却负载过高的情况,有效地利用了系统资源,提高了服务的整体处理能力和响应速度。

  1. 负载均衡策略配置
    开发人员可以根据实际业务需求灵活配置 Ribbon 的负载均衡策略。比如,对于那些对响应时间比较敏感的服务调用场景,可以配置为加权响应时间策略,该策略会根据各个服务实例过往的响应时间数据来动态分配请求权重,响应时间短的实例会被分配更多的请求,使得整体的服务响应更加高效;而对于一些对请求均匀分布要求较高,不特别关注实例性能差异的场景,轮询策略就是一个简单且有效的选择。

以下是一个简单的配置示例,假设要将对 user-service 的负载均衡策略修改为随机策略,可以在项目的配置文件(如 application.yml 或 application.properties)中添加如下配置:

user-service:ribbon:NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

在上述配置中,user-service 对应着要配置负载均衡策略的服务名称(需和 @FeignClient 注解中指定的名称一致),通过 ribbon.NFLoadBalancerRuleClassName 属性指定了采用 RandomRule(随机策略),这样 Feign 在调用 user-service 时就会按照随机的方式选择服务实例进行请求发送,满足了特定场景下的负载均衡需求。

(四)响应处理与类型转换

  1. 响应解析
    Feign 在接收到远程服务返回的 HTTP 响应后,会对响应进行解析处理。它会根据响应的内容类型(如 JSON、XML 等)以及接口方法定义时预期的返回类型,自动进行数据的提取和转换工作。

例如,如果远程服务返回的是 JSON 格式的用户信息数据,而 Feign 接口方法定义的返回类型是 User 实体类(假设 User 类有对应的属性与 JSON 数据中的字段对应),Feign 会利用内置的 JSON 解析器(通常默认使用 Jackson 或 Gson,也可以进行配置替换)将 JSON 字符串解析为 User 类型的对象。这一过程对于开发人员来说是透明的,无需手动编写大量的 JSON 解析代码,就像在本地方法调用返回了一个普通对象一样自然,极大地简化了对响应数据的处理流程。

  1. 错误处理与异常转换
    在服务调用过程中,如果出现 HTTP 状态码表示的错误情况(如 404 表示资源未找到、500 表示服务器内部错误等)或者远程服务返回的响应中包含了表示错误的特定数据结构(如带有错误码和错误消息的 JSON 结构体),Feign 会将这些情况进行统一的异常转换处理,将 HTTP 错误或者业务逻辑层面的错误包装成合适的 Java 异常,抛回到调用方代码中。

例如,如果远程 user-service 在处理 getUserById 请求时返回了 404 状态码,Feign 会捕获这个情况,并抛出一个对应的异常(如 FeignException 等相关异常类型),在调用 userServiceClient.getUserById(userId) 的代码处就可以通过捕获异常来进行相应的处理,比如记录日志、提示用户等,使得开发人员能够方便地处理服务调用过程中出现的各种错误情况,保障业务逻辑的健壮性。

四、Feign 的优点

(一)简洁的代码风格与开发效率提升

  1. 声明式调用
    Feign 采用声明式的接口定义方式来进行服务间调用,使得代码结构非常清晰简洁。开发人员只需要关注接口定义以及业务逻辑中对接口方法的调用,无需像传统的 HTTP 客户端那样编写大量繁琐的代码来构建请求、处理响应等。例如,对比使用 java.net.HttpURLConnection 手动发起 HTTP 请求的方式,使用 Feign 可以从几十行甚至上百行的代码量减少到简单的几行接口定义和方法调用代码,大大提高了代码的可读性和可维护性。

以下是使用 java.net.HttpURLConnection 发起一个简单的 GET 请求获取用户信息的示例代码(仅为示意,实际可能更复杂):

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;public class ManualHttpRequestExample {public static void main(String[] args) throws IOException {String url = "http://user-service/users/123";URL obj = new URL(url);HttpURLConnection con = (HttpURLConnection) obj.openConnection();con.setRequestMethod("GET");int responseCode = con.getResponseCode();if (responseCode == HttpURLConnection.HTTP_OK) {BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));String inputLine;StringBuilder response = new StringBuilder();while ((inputLine = in.readLine())!= null) {response.append(inputLine);}in.close();// 这里还需要手动解析返回的 JSON 等格式的数据为对应的对象,暂省略解析代码System.out.println("响应内容: " + response.toString());} else {System.out.println("请求失败,状态码: " + responseCode);}}
}

而使用 Feign,如前面所展示的,只需要定义一个简单的接口并在业务逻辑中调用接口方法即可,代码量和复杂度都大幅降低,让开发人员能够更快地实现服务间的调用逻辑,专注于核心业务功能的开发,从而有效提升了整个项目的开发效率。

  1. 快速原型开发
    在项目的早期阶段,尤其是进行快速原型开发时,Feign 的简洁性优势更加明显。开发团队可以迅速地根据业务需求定义各个微服务之间的调用接口,快速搭建起微服务之间的交互框架,而不用花费大量时间在处理底层的通信细节上。例如,在一个创新型的互联网应用项目中,产品经理提出了新的功能需求,涉及多个微服务之间的协作,开发人员利用 Feign 能够在短时间内实现各个微服务之间初步的调用逻辑,快速构建出功能原型,方便与产品经理、测试人员等进行沟通和验证,根据反馈及时调整和完善功能,加快了项目的迭代速度,使得产品能够更快地推向市场。

(二)与 Spring Cloud 生态的深度融合

  1. 一站式集成体验
    Feign 作为 Spring Cloud 生态中的重要一员,能够与其他 Spring Cloud 组件无缝集成,为开发人员提供了一站式的微服务开发体验。它可以与服务注册与发现组件(如 Eureka、Nacos 等)配合实现动态的服务地址获取和调用,与负载均衡组件 Ribbon 协同进行请求的负载均衡分配,还能与熔断器组件(如 Hystrix)结合来实现服务调用的容错处理(后面会详细介绍其与 Hystrix 的集成),以及与配置管理组件等共同构建起完整的、健壮的微服务架构。

例如,在一个基于 Spring Cloud 的电商微服务项目中,商品微服务、订单微服务、用户微服务等通过 Feign 进行相互调用,同时借助 Eureka 进行服务注册与发现、Ribbon 进行负载均衡、Hystrix 进行熔断保护,开发人员只需要在项目中添加相应的依赖并进行简单的配置,就能轻松实现这些功能的集成,无需在不同的框架和工具之间进行复杂的适配和整合工作,降低了开发的复杂性和技术门槛,提高了项目整体的集成效率和稳定性。

  1. 统一的配置管理
    Spring Cloud 提供了统一的配置管理机制,Feign 也能够很好地融入其中。开发人员可以通过配置文件(如 application.yml 或 application.properties)对 Feign 的各种参数进行集中管理,比如设置请求超时时间、配置日志级别、调整负载均衡策略等。这种统一的配置管理方式使得在项目的不同环境(开发环境、测试环境、生产环境等)中,能够方便地对 Feign 的行为进行调整和优化,保证其在各个环境下都能按照预期工作,同时也便于对项目的配置进行维护和版本控制,减少了因配置分散导致的错误和管理成本。

以下是一些常见的 Feign 配置示例:

feign:client:config:default:# 设置连接超时时间,单位为毫秒connectTimeout: 5000# 设置读取超时时间,单位为毫秒readTimeout: 5000# 配置日志级别,可选择 NONE、BASIC、HEADERS、FULLloggerLevel: FULL

在上述配置中,通过 feign.client.config.default 前缀可以对 Feign 的默认配置进行设置,这里分别设置了连接超时时间和读取超时时间为 5000 毫秒,以及将日志级别设置为 FULL,这样在调试和查看 Feign 服务调用情况时能够获取到更详细的日志信息,方便开发人员排查问题和优化性能。

(三)强大的容错能力与服务降级支持

  1. 与 Hystrix 的集成
    Feign 可以很方便地与 Hystrix 集成,实现服务调用的熔断和降级功能。当被调用的微服务出现故障(如响应时间过长、频繁出错等情况),满足 Hystrix 设定的熔断条件时,Hystrix 会自动切断对该服务的调用链路,转而执行预先定义的降级逻辑,避免故障服务进一步影响整个系统的正常运行,起到了保护系统的作用。

例如,我们在之前定义的 UserServiceClient 接口基础上,结合 Hystrix 来实现服务降级功能。首先需要在项目中引入相关依赖并开启 Hystrix 对 Feign 的支持,在 pom.xml 文件(基于 Maven 构建的项目)中添加如下依赖:

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

然后在配置文件(如 application.yml)中配置 feign.hystrix.enabled 属性为 true,开启 Hystrix 对 Feign 的支持,如下:

feign:hystrix:enabled: true

接着,修改 UserServiceClient 接口,为其指定降级实现类,代码如下:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;@FeignClient(name = "user-service", fallback = UserServiceFallback.class)
public interface UserServiceClient {@GetMapping("/users/{id}")User getUserById(@PathVariable("id") String id);
}

这里通过 fallback 属性指定了 UserServiceFallback 为降级类,我们再来定义这个降级类,它需要实现 UserServiceClient 接口,并实现接口中的方法来提供降级逻辑,示例如下:

import org.springframework.stereotype.Component;@Component
public class UserServiceFallback implements UserServiceClient {@Overridepublic User getUserById(String id) {// 返回一个默认的用户对象或者提示信息等,这里简单返回null并打印提示信息System.out.println("用户服务调用出现故障,执行降级逻辑");return null;}
}

这样,当调用 user-service 出现问题触发熔断条件后,就会执行 UserServiceFallback 类中的 getUserById 方法,返回默认的降级结果,防止因为用户服务的故障导致依赖它的其他业务逻辑(比如订单服务中的相关逻辑)出现长时间阻塞或者异常崩溃的情况,保障了系统整体的稳定性和可用性。

  1. 服务降级策略灵活运用
    除了与 Hystrix 集成实现基于熔断的服务降级外,开发人员还可以根据业务场景灵活制定各种服务降级策略。比如在电商大促期间,如果推荐服务因为流量过大出现性能问题,我们可以通过 Feign 定义的接口为推荐服务调用设置降级逻辑,返回一些预定义的热门商品推荐列表,而不是尝试去获取个性化的推荐内容,确保用户依然能够在页面上看到相关商品推荐,能够继续正常进行购物流程,虽然推荐的精准度有所下降,但保障了核心购物功能不受影响,提升了用户体验。

又比如,对于某个查询服务,在数据库连接出现短暂故障时,可以通过降级逻辑返回缓存中的部分旧数据(前提是缓存中有可用数据且允许使用旧数据的场景),让用户看到一些相关信息,而不是直接给用户展示错误页面,待数据库恢复正常后再更新缓存并提供准确的数据,这种灵活的服务降级策略可以根据不同的业务需求和故障情况进行定制,使得系统在面对各种复杂的运行状况时都能尽可能地保障关键业务的正常开展。

(四)便于测试与维护

  1. 单元测试友好性
    Feign 接口的定义方式使得对其进行单元测试变得相对容易。由于接口的调用逻辑是声明式的,在进行单元测试时,我们可以方便地使用 Mock 框架(如 Mockito 等)来模拟远程服务的响应,从而独立地测试业务逻辑代码对 Feign 接口的调用是否正确,而无需真正去启动对应的远程服务,也不用担心网络环境、远程服务状态等外部因素对测试结果的影响。

例如,针对前面的 OrderService 类中调用 UserServiceClient 接口的 processOrder 方法,我们可以使用 Mockito 来进行单元测试,示例如下:

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
public class OrderServiceTest {@Testpublic void testProcessOrder() {UserServiceClient userServiceClient = Mockito.mock(UserServiceClient.class);// 模拟返回一个特定的用户对象User mockUser = new User("123", "John Doe", "example@example.com");Mockito.when(userServiceClient.getUserById("123")).thenReturn(mockUser);OrderService orderService = new OrderService(userServiceClient);orderService.processOrder("123");// 可以在这里添加更多的断言来验证业务逻辑是否正确处理了获取到的用户信息,比如验证是否进行了权限验证等操作Mockito.verify(userServiceClient).getUserById("123");}
}

在上述测试代码中,首先使用 Mockito.mock 方法创建了 UserServiceClient 接口的 Mock 对象,然后通过 Mockito.when 方法模拟了当调用 getUserById 方法并传入参数 "123" 时返回一个特定的 User 对象,接着创建 OrderService 类的实例并调用 processOrder 方法,最后通过 Mockito.verify 方法验证了 getUserById 方法确实被调用了,这样就可以在不依赖真实远程服务的情况下,对 OrderService 类中与 UserServiceClient 接口调用相关的业务逻辑进行有效的单元测试,便于及时发现代码中的逻辑错误,提高代码质量。

  1. 代码维护与演进
    Feign 的代码结构清晰,接口定义与业务逻辑分离,使得在项目后续的维护和演进过程中更加容易操作。如果远程服务的接口发生了变化(比如新增了请求参数、修改了返回数据结构等),只需要在对应的 Feign 接口定义处进行相应的修改,更新注解、参数类型或者返回类型等内容,就能快速适配这种变化,而不会对大量的业务逻辑代码造成过多的影响。

例如,假设 user-service 中的 getUserById 接口新增了一个表示是否获取详细信息的布尔型参数,我们只需要在 UserServiceClient 接口定义中修改 getUserById 方法如下:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;@FeignClient(name = "user-service")
public interface UserServiceClient {@GetMapping("/users/{id}")User getUserById(@PathVariable("id") String id, @RequestParam("isDetailed") boolean isDetailed);
}

然后在调用该接口方法的业务逻辑代码中,根据新的参数要求传递相应的值即可,这样的修改相对集中在 Feign 接口定义部分,对于整个项目中其他依赖这个接口的业务逻辑代码,只要按照新的参数要求进行适当调整就能继续正常工作,大大降低了因为服务接口变化带来的维护成本,使得项目能够更加灵活地进行功能扩展和迭代升级。

(五)跨服务的一致性与标准化

  1. 接口定义标准化
    Feign 通过让开发人员以接口的形式定义服务间的调用,促使各个微服务团队在设计对外提供的服务接口时更加注重标准化。不同团队开发的微服务,只要遵循统一的接口定义规范(比如统一的请求路径命名规则、参数传递方式、返回数据格式等),就能方便地通过 Feign 进行相互调用,减少了因为接口风格不一致导致的沟通成本和集成困难。

例如,在一个大型的企业级微服务架构项目中,财务微服务、人力资源微服务、销售微服务等不同的业务微服务在对外提供获取数据或者执行操作的接口时,如果都采用 Feign 推荐的接口定义方式,使用标准的 HTTP 方法注解(如 @GetMapping@PostMapping 等)以及规范的参数绑定和返回类型处理,那么各个微服务之间的交互就会更加顺畅,新加入的微服务团队也能快速了解并遵循已有的接口定义规范,方便地融入到整个项目的微服务体系中,提高了整个系统的集成效率和可扩展性。

  1. 统一的交互体验
    对于使用 Feign 进行服务调用的客户端代码来说,无论调用的是哪个微服务,其调用方式和代码风格都是相似的,都呈现出一种声明式的、简洁的调用体验。这就好比在不同的商店购物(调用不同微服务),虽然售卖的商品(提供的服务内容)不同,但购物的流程(调用的方式)基本是统一的,开发人员只需要熟悉 Feign 的接口定义和调用方法,就能轻松地与各个微服务进行交互,无需针对不同的微服务学习和适应不同的调用方式,降低了开发人员的学习成本,也使得整个项目的代码风格更加统一、规范,便于理解和维护。

五、总结

Feign 作为一个声明式的 HTTP 客户端,在微服务架构中扮演着极为重要的角色。它通过简洁的接口定义方式、与 Spring Cloud 生态的深度融合、强大的容错能力、便于测试维护以及促进跨服务的一致性与标准化等诸多优点,极大地简化了微服务之间的调用流程,提升了开发效率、系统稳定性以及代码的可维护性和可扩展性。

相关文章:

深度解析 Feign

一、引言 在当今微服务架构盛行的时代&#xff0c;众多微服务相互协作构成了复杂的分布式系统。然而&#xff0c;各个微服务之间的调用往往涉及到诸多繁琐的细节&#xff0c;比如网络请求的构建、参数的处理、响应的解析等。为了让开发人员能够更加专注于业务逻辑的实现&#x…...

AI工业大模型报告:体系架构、关键技术与典型应用

研究意义 随着新一代人工智能的发展, 大模型&#xff08;如 GPT-4o 等&#xff09;凭借大规模训练数据、网络参数和算 力涌现出强大的生成能力、泛化能力和自然交互能力, 展现出改变工业世界的巨大潜力. 尽管大模型 已在自然语言等多个领域取得突破性进展, 但其在工业应用中的…...

深入理解接口测试:实用指南与最佳实践5.0(五)

✨博客主页&#xff1a; https://blog.csdn.net/m0_63815035?typeblog &#x1f497;《博客内容》&#xff1a;.NET、Java.测试开发、Python、Android、Go、Node、Android前端小程序等相关领域知识 &#x1f4e2;博客专栏&#xff1a; https://blog.csdn.net/m0_63815035/cat…...

常用List工具类(取交集、并集等等)

支持操作&#xff1a; 根据指定字段&#xff0c;获取两个对象集合的交集、补集、并集等将对象中的多个字段值&#xff0c;抽取到一个List中 import java.lang.reflect.Field; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function…...

4 C++ 复合类型:引用和指针

复合类型是指基于其它类型定义的类型。C 有几种复合类型&#xff0c;包括引用、指针。 1 引用 引用&#xff08;reference&#xff09;为对象起了另外一个名字&#xff0c;引用类型引用另外一种类型。通过将声明符写成&d的形式来定义引用类型&#xff0c;其中d是声明的变量…...

ABAP关于PS模块CJ20N中项目物料的屏幕和字段增强CI_RSADD

网上搜关于CJ20N的屏幕增强,基本都是关于项目定义(CI_PROJ)、项目WBS(CI_PRPS)、项目网络活动工序(CI_AFVU)的字段与屏幕增强,几乎没有关于项目物料(CI_RSADD)的字段屏幕增强,我在这里做一个分享。 主要逻辑:实现badi增强,并自建一个函数组后创建屏幕,在badi里面调用…...

探索IDE的无限可能:使用技巧与插件推荐

在软件开发的世界里&#xff0c;集成开发环境&#xff08;IDE&#xff09;是开发者的得力助手&#xff0c;它不仅提供了代码编辑、编译、调试等功能&#xff0c;还通过各种插件扩展了其功能&#xff0c;使得开发工作更加高效和便捷。本文将带你探索IDE的使用技巧和一些实用的插…...

自动化生成测试用例:利用OpenAI提升电商网站测试覆盖率

导语 自动化生成测试用例是软件测试领域一个强大的应用&#xff0c;通过OpenAI的语言模型&#xff0c;测试工程师可以快速生成高质量的测试用例&#xff0c;尤其是在处理边界条件和极端情况时&#xff0c;提升测试覆盖率。本篇文章将结合一个典型的电商网站案例&#xff0c;介绍…...

时间序列关于可解释性值得关注的论文汇总-第2篇

前言 这是时序可解释性论文汇总的第二篇&#xff0c;第一篇见这里&#xff08;后台回复&#xff1a;“论文合集”可直接获取整理的文章&#xff09;。深度学习的可解释性研究一直是热门&#xff0c;而时间序列的可解释性同样非常重要。这是因为时序模型被大量应用到特定领域&a…...

Vulnhub:DC-4靶机渗透——土豆片的靶机渗透练习

攻击机&#xff1a;kali 靶机&#xff1a;DC-4 一&#xff0c;信息收集 1.主机发现 找寻同网段下存活的主机 arp-scan -l2.端口扫描 查看此主机上有哪些开放端口 nmap -sV -p- 192.168.126.136发现22&#xff0c;80端口&#xff0c;远程连接跟网站&#xff08;大概&…...

【云原生系列--Longhorn的部署】

Longhorn部署手册 1.部署longhorn longhorn架构图&#xff1a; 1.1部署环境要求 kubernetes版本要大于v1.21 每个节点都必须装open-iscsi &#xff0c;Longhorn依赖于 iscsiadm主机为 Kubernetes 提供持久卷。 apt-get install -y open-iscsiRWX 支持要求每个节点都安装 N…...

Java集合(Collection+Map)

Java集合&#xff08;CollectionMap&#xff09; 为什么要使用集合&#xff1f;泛型 <>集合框架单列集合CollectionCollection遍历方式List&#xff1a;有序、可重复、有索引ArrayListLinkedListVector&#xff08;已经淘汰&#xff0c;不会再用&#xff09; Set&#xf…...

微信小程序02-页面制作

微信小程序页面制作指南 目录 微信小程序页面制作 1. 个人信息展示小程序 案例分析 需求背景&#xff1a;许多大学生毕业后需要求职&#xff0c;因此制作一个展示个人信息的微信小程序对招聘人员快速了解求职者非常有帮助。页面布局&#xff1a;页面分为头像区域和详细信息…...

zabbix监控端界面时间与服务器时间不对应

1. 修改系统时间 # tzselect Please select a continent, ocean, "coord", or "TZ".1) Africa2) Americas3) Antarctica4) Asia5) Atlantic Ocean6) Australia7) Europe8) Indian Ocean9) Pacific Ocean 10) coord - I want to use geographical coordina…...

端对端加密是如何通过SDK防御实现的?

端对端加密&#xff08;End-to-End Encryption&#xff0c;E2EE&#xff09;是一种确保数据在传输过程中不被第三方截获和篡改的技术。随着网络安全威胁的日益增多&#xff0c;端对端加密在即时通讯、文件传输等领域变得越来越重要。本文将详细介绍如何通过SDK&#xff08;Soft…...

Flutter:input输入框

输入框&#xff1a; // 是否显示关闭按钮 bool _showClear false; // 文字编辑控制器&#xff0c;监听搜索框的变化。 final TextEditingController _controller TextEditingController(); // 输入框发生变化事件 void _onChange(String value){if(value.length > 0){setS…...

RabbitMQ 与 PHP Swoole 实现

RabbitMQ 与 PHP Swoole 的结合实现 一、概述 RabbitMQ 是一个开源的消息队列中间件&#xff0c;允许通过异步消息传递来解耦应用程序的各个部分。Swoole 是一个高性能的 PHP 扩展&#xff0c;支持异步编程和协程&#xff0c;适用于构建高并发的网络服务。将 RabbitMQ 与 Swo…...

【计算机体系架构】 MESI缓冲一致性

高并发学习参考 https://blog.csdn.net/MrYushiwen/article/details/123049838 https://cloud.tencent.com/developer/article/2197857 ESI 是指Cache 行的三种一致性状态&#xff1a;E&#xff08;Exclusive&#xff0c;独占&#xff09;&#xff0c;S&#xff08;Shared&…...

STM32设计学生宿舍监测控制系统

目录 前言 一、本设计主要实现哪些很“开门”功能&#xff1f; 二、电路设计原理图 电路图采用Altium Designer进行设计&#xff1a; 三、实物设计图 四、程序源代码设计 五、获取资料内容 前言 随着科技的飞速发展和智能化时代的到来&#xff0c;学生宿舍的安全、舒适…...

企业生产环境-麒麟V10(ARM架构)操作系统部署kafka高可用集群

前言&#xff1a;Apache Kafka是一个分布式流处理平台&#xff0c;由LinkedIn开发并捐赠给Apache软件基金会。它主要用于构建实时数据流管道和流应用。Kafka具有高吞吐量、可扩展性和容错性的特点&#xff0c;适用于处理大量数据。 以下是Kafka的一些核心概念和特性&#xff1…...

awk(常用)

这个有点难 O.o 一、awk # 语法 awk 参数 模式 {动作} 文件# 第一列&#xff0c;包含p的 $1~"p" # 第一列&#xff0c;不包含p的 $1!~"p" # 开始时干嘛&#xff0c;结束时干嘛 awk BEGIN{开始时做的事}END{结束时做的事}{print $0} 文件 1、内置变量&…...

Amazon Web Services (AWS)

一、Amazon Web Services (AWS)介绍 1、简介 2、产品 AWS 提供了各种云计算服务&#xff0c;包括 DynamoDB、S3、EC2、Lambda 等等。 登录aws后点击所有服务也可以看到amazon的所有服务&#xff1a; 3、免费试用产品 除了免费的Amazon Step Functions、Amazon Lambda&#…...

Java EE 技术基础知识体系梳理

1. Java EE 平台概述 1.1 发展历程 Java EE 从 J2EE 发展而来&#xff0c;经历了多个版本的演进&#xff0c;从早期的 J2EE 1.2 到最新的 Jakarta EE。 1.2 架构特点 多层架构&#xff1a; 客户端层&#xff1a;用户界面&#xff0c;如 Web 浏览器、移动应用等。Web 层&…...

【2025最新计算机毕业设计】基于SpringBoot+Vue电脑在线装机指南教程网站【源码+文档】

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…...

HDFS新增节点和删除datanode节点

在实际的hadoop环境中&#xff0c;有时我们需要新增或者删除datanode节点&#xff0c;来达到扩容或缩容的目的&#xff0c;本文就来讲解如何新增和删除datanode。 新增节点和删除节点会涉及两个关键的配置项&#xff08;hdfs-site.xml文件中&#xff09;&#xff1a; dfs.hos…...

数据结构-线性表-具有独立头节点的双向循环链表

完整代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS #pragma warning(disable:6013)#include<stdio.h> #include<malloc.h> #include<stdlib.h> #include<time.h>// 一个具有独立头节点的双向循环链表&#xff0c; // 区别在于将头节点和数据区域…...

CSS 响应式设计之媒体查询技术

CSS 媒体查询&#xff08;Media Queries&#xff09;是一种根据不同设备的特性&#xff08;如屏幕宽度、分辨率、方向等&#xff09;来应用不同的 CSS 样式的技术。它通常用于响应式设计&#xff0c;帮助网页在不同设备和屏幕尺寸下良好地展示。 基本语法 media (条件) {/* 样…...

HARCT 2025 分论坛4:智能系统传感、传感器开发和数据融合中的智能数据分析

机电液一体化与先进机器人控制技术国际会议&#xff08;HARCT 2025&#xff09;将于2025年1月3日-6日在中国广西桂林召开。本届会议围绕“机电液一体化”“机器人”“控制技术”等最新研究成果&#xff0c;邀请海内外在这一领域贡献卓著的专家学者做精彩致辞和报告。 会议期间…...

云计算研究实训室建设方案

一、引言 随着云计算技术的迅速发展和广泛应用&#xff0c;职业院校面临着培养云计算领域专业人才的迫切需求。本方案旨在构建一个先进的云计算研究实训室&#xff0c;为学生提供一个集理论学习、实践操作、技术研发与创新于一体的综合性学习平台&#xff0c;以促进云计算技术…...

VRT: 关于视频修复的模型

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;编程探索专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月15日14点34分 神秘男子影, 秘而不宣藏。 泣意深不见, 男子自持重, 子夜独自沉。 论文链接 点击开启你的论文编程之旅…...