在 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");
}执行结果:

上述示例中,@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");
}执行结果:

上面代码中,@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");
}执行结果:

上面代码中,@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 代码如下:
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() 方法,输出结果如下:
