Netflix Feign @Param 注解

在 Netflix Feign 中,@Param 注解主要用于将方法参数绑定到请求的参数中。它允许你在定义 Feign 客户端接口方法时,明确指定方法参数如何映射到请求的 URL 参数、请求头或者请求体中,使得远程服务调用能够正确地传递参数信息。

注意:@Param 可以与 @RequestLine、@Headers 和 @Body 注解配合使用。

应用示例

绑定查询参数

通过 @Param 定义参数,然后将参数绑定到请求查询参数,例如:

(1)服务代码:

@GetMapping("/param1")
public String param1(@RequestParam("token") String token) {
    return "token=" + token;
}

(2)Feign 客户端代码:

@RequestLine("GET /simple/param1?token={token}")
String param1(@Param("token") String token);

(3)调用 Feign 客户端代码:

@GetMapping("/")
public String index() {
    return SimpleFeign.create().param1("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
}

执行结果:

f14369aa1ae90091fefb1b294ef53f86_1730367765747-59bb5f83-dfc0-448b-a5b3-355a71693b0f.png

上述示例中,@RequestLine("GET /simple/param1?token={token}") 定义了一个 GET 请求,其中 {token} 是一个变量。@Param("token") String token 表示方法参数 token 将被绑定到路径中的 {token} 变量上(可以理解为 {token} 引用了 @Param("token") 定义的参数)。

当调用 param1 方法并传入一个 token(例如 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855)时,Netflix Feign 会构建一个类似 /simple/param1?token=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 的请求路径发送到目标服务。

绑定请求头

如果你想将一个参数绑定到请求头中,可以结合 @RequestHeader(Feign 中的另一个注解,后续将详细介绍)来实现。假设你需要传递一个认证令牌(token)到请求头中,例如:

(1)服务代码:

@GetMapping("/param2")
public String param2(@RequestHeader("Authorization") String token) {
    return "Authorization=" + token;
}

(2)Feign 客户端代码:

@RequestLine("GET /simple/param2")
@Headers("Authorization: Bearer {token}")
String param2(@Param("token") String token);

(3)调用 Feign 客户端代码:

@GetMapping("/")
public String index() {
    return SimpleFeign.create().param2("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
}

执行结果:

411bcd83d8b86c9d754b44a4ced85a81_1730367110106-7ca54c22-11d7-4b22-9ec0-d8a5b13302b8.png

上面代码中,@Headers("Authorization: Bearer {token}") 表示引用方法参数 token,将 token 的值以Authorization 这个请求头的名称进行传递。例如,如果 token 的值为 Bearer 123456,Feign 会在请求头中添加 Authorization: Bearer 123456,然后发送 GET 请求到 /simple/param2 端点。

绑定请求体

如果你想将一个参数绑定到请求体中,可以结合 @Body 注解(Feign 中的另一个注解,后续将详细介绍)来实现。假设你需要通过请求体传递一段文本(注意:传递请求体请使用 POST 请求),例如:

(1)服务代码:

@PostMapping("/param3")
public String param3(@RequestBody String body) {
    return "body=" + body;
}

(2)Feign 客户端代码:

@RequestLine("POST /simple/param3")
@Body("{body}")
String param3(@Param("body") String body);

(3)调用 Feign 客户端代码:

@GetMapping("/")
public String index() {
    return SimpleFeign.create().param3("hello! body");
}

执行结果:

97e447a26b549efffa81252ad2fa4aae_1730368575127-5f57bc61-8ff5-427a-9375-2dd46fe83649.png

上面代码中,@Body("{body}") 表示引用方法参数 body,将 body 的值以请求体的方式进行传递。

源码分析

下面是 @Param 注解的源码:

package feign;

import java.lang.annotation.Retention;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * A named template parameter applied to {@link Headers}, {@linkplain RequestLine},
 * {@linkplain Body}, POJO fields or beans properties when it expanding
 * 用于 @Headers、@RequestLine、@Body,POJO 字段或 Bean 属性的已命名模板参数。
 */
@Retention(RUNTIME)
@java.lang.annotation.Target({PARAMETER, FIELD, METHOD})
public @interface Param {

  /**
   * The name of the template parameter.
   * 模板参数的名称。
   */
  String value() default "";

  /**
   * How to expand the value of this parameter, if {@link ToStringExpander} isn't adequate.
   * 如果 ToStringExpander 不满足要求,你可以自定义 Expander 扩展器。
   */
  Class<? extends Expander> expander() default ToStringExpander.class;

  /**
   * {@code encoded} has been maintained for backward compatibility and should be deprecated. We no
   * longer need it as values that are already pct-encoded should be identified during expansion and
   * passed through without any changes
   * encoded 是为了向后兼容而保留的,应予废弃。我们不再需要它,因为已被 pct-encoded 的
   * 值应在扩展过程中识别出来,并在不做任何更改的情况下通过
   *
   * @see QueryMap#encoded
   * @deprecated 已过期,不建议使用
   */
  boolean encoded() default false;

  interface Expander {
    /**
     * Expands the value into a string. Does not accept or return null.
     * 将数值扩展为字符串。不接受或返回空值。
     */
    String expand(Object value);
  }

  // 默认实现,将对象转为字符串
  final class ToStringExpander implements Expander {
    @Override
    public String expand(Object value) {
      return value.toString();
    }
  }
}

自定义 Expander

下面演示如何自定义 Expander,该 Expander 将在值的前后添加一些固定字符串。Expander 代码如下:

class MyExpander implements Param.Expander {
    @Override
    public String expand(Object value) {
        return "123" + value + "321";
    }
}

在 Feign 中,使用自定义的 Expander,如下:

@RequestLine("POST /simple/param3")
@Body("{body}")
String param4(@Param(value = "body", expander = MyExpander.class) String body);

调用 param4() 方法,输出结果如下:

3e9fca8d128a5f28be9ded16cd404401_1730428829702-16ff4291-0964-4afa-8bef-7c554304074b.png

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