OpenFeign 定义 Feign 客户端

前面通过“Spring Cloud OpenFeign 入门示例”已经了解了如何通过 OpenFeign 定义一个 Feign 客户端,然后通过该 Feign 客户端发起 HTTP 远程调用,下面将更全面的介绍如何去定义 Feign 客户端,让我们有一个更清晰的认识。

定义 Feign 客户端详细步骤如下:

第一步:引入 Feign 依赖

确保你的项目中已经引入了 Feign 相关的依赖。在 Maven 项目中,需要在pom.xml文件中添加如下依赖:

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

注意:这将引入 Feign 的核心功能以及与 Spring Cloud 集成所需的组件。

第二步:创建 Feign 客户端接口

定义一个接口,这个接口将作为 Feign 客户端接口(注意:通常的做法是创建一个 feign 包,将所有 Feign 客户端均放到该包下面)。

例如,假设你要调用一个demo服务的接口来获取用户信息,接口可能如下:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "service-demo")
public interface UserFeign {

    @GetMapping("/users/{id}")
    User getUserById(@PathVariable("id") Long id);
    //...更多...
    
}

上面代码中,@FeignClient 注解是关键。它有一个 name 属性(也可以使用 value 属性,它们的作用相同),这个属性的值 service-demo 通常是你要调用的服务在注册中心中的服务名(一个服务名可能对应多个具体的服务实例,有关注册中心,可以学习 Spring Cloud Alibaba Nacos 教程 或 Netflix Eureka 教程)。

UserFeign 接口中的方法定义了具体的远程调用方法。@GetMapping 注解用于指定 HTTP 的 GET 请求方式,并且路径 /users/{id} 表示调用远程服务中这个路径下的接口。@PathVariable 注解用于将方法参数绑定到路径变量中,这样在发送请求时,{id} 部分会被实际的参数值替换。

💥注意,Spring Cloud OpenFeign 沿用了 Spring MVC 的注解,这样可以减少开发人员的学习成本,如常用注解 @GetMapping、@PostMapping、@RequestParam、@RequestBody 等注解,这也是与 Netflix Feign 的区别,Netflix Feign 定义了自己的注解,如 @RequestLine、@Body、@Headers、@Param 等,点击学习 Netflix Feign 教程

如果我们在项目中创建了两个 Feign 客户端(即两个接口),并且使用的 @FeignClient(name = "service-demo") 相同。那么,项目启动时会抛出如下错误:

The bean 'SERVICE-DEMO.FeignClientSpecification' could not be registered. A bean with that name has already been defined and overriding is disabled.

这是因为 Spring Cloud 会为每个 @FeignClient 注解创建一个 FeignClientSpecification Bean。这些 Bean 的名称是根据 @FeignClient 注解中的 value 属性生成的,格式为:

${value}.FeignClientSpecification

解决办法:

方法一:修改配置,允许 Bean 覆盖(谨慎使用💥

可以通过修改配置文件,允许 Bean 定义覆盖。在 application.properties 文件中添加如下内容:

spring.main.allow-bean-definition-overriding=true

或者在 application.yml 文件中添加如下内容:

spring:
  main:
    allow-bean-definition-overriding: true

不过这种方法可能会隐藏一些潜在的问题。如果有其他同名 Bean 在不期望的情况下被覆盖,可能会导致难以调试的错误。所以这只是一个临时解决方案,在使用时需要谨慎考虑。

方法二:修改 @FeignClient 注解的 contextId 属性(推荐👍

@FeignClient 注解有一个 contextId 属性,这个属性可以用来为每个 FeignClient 指定一个唯一的标识符。当没有显式设置 contextId 时,它默认会使用 value 属性的值。

例如,修改接口定义如下:

@FeignClient(value="service-demo", contextId="serviceDemo1")
public interface ServiceDemoInterface1 {
  // 接口方法定义
}

@FeignClient(value="service-demo", contextId="serviceDemo2")
public interface ServiceDemoInterface2 {
  // 接口方法定义
}

上面代码通过为每个 @FeignClient 注解指定不同的 contextId,Spring Cloud 会为每个 FeignClient 创建具有不同名称的 FeignClientSpecification Bean,从而避免了同名 Bean 的冲突。

第三步:配置 Feign 客户端(可选)

在实际使用中,你可能需要对 Feign 客户端进行一些配置,比如设置请求超时时间、日志级别等等。

在 Spring Boot 项目中,可以通过创建一个 FeignConfig 配置类实现配置,例如:

package com.hxstrive.demo_springcloud_openfeign.config;

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

/**
 * Feign 配置类
 * @author hxstrive.com
 */
@Configuration
public class FeignConfig {

    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }

}

这个配置类中定义了一个 feignLoggerLevel 方法,返回 Logger.Level.FULL,这将使 Feign 在调用时打印出完整的日志信息,包括请求和响应的详细内容,方便调试。你还可以通过这个配置类设置其他的属性,如连接超时时间和读取超时时间等。关于日志更详细的说明查看后续章节……

第四步:启用 Feign 客户端

在 Spring Cloud 应用的启动类上,需要使用 @EnableFeignClients 注解来启用 Feign 客户端。例如:

package com.hxstrive.demo_springcloud_openfeign;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
// 启动 Feign 客户端
@EnableFeignClients
public class DemoOpenFeignApplication {

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

}

注意,@EnableFeignClients 注解会扫描项目中定义的 Feign 客户端接口,并将它们注册到 Spring 容器中,使得它们可以被自动注入和使用。

到这里 Feign 客户端创建完成了。

通过以上步骤,你就可以定义一个 Feign 客户端接口,用于调用远程服务。当你需要使用这个接口时,你可以将它注入到其他的 Spring 组件(如 Service、Controller 等)中,就像使用普通的 Java 接口一样,而 Feign 会在幕后处理与远程服务的通信。更多知识请关注后续章节……

说说我的看法
全部评论(
没有评论
关于
本网站专注于 Java、数据库(MySQL、Oracle)、Linux、软件架构及大数据等多领域技术知识分享。涵盖丰富的原创与精选技术文章,助力技术传播与交流。无论是技术新手渴望入门,还是资深开发者寻求进阶,这里都能为您提供深度见解与实用经验,让复杂编码变得轻松易懂,携手共赴技术提升新高度。如有侵权,请来信告知:hxstrive@outlook.com
公众号