Spring Cloud的Feign客户端入门


在本教程中,我们将了解FeignClient以及如何在Spring Boot/Spring Cloud应用程序中使用它。
FeignClient是一个以声明方式创建REST API客户端的库。因此,如果我们不是手动编写远程API客户端,就可能使用Springs RestTemplate,而使用Feign声明客户端定义很方便,其余部分在运行时生成供使用。

我们将构建一个小型命令行应用程序,它模拟我们一个看板API的完整测试。示例应用程序将创建一个新用户,登录,检索所有板并再次注销用户。它捕获了最常见的用例(POST,GET,DELETE + AuthN)

添加依赖项
我们在本教程中使用Maven。由于我们不想弄乱版本号,最简单的方法是在Maven POM 中的dependencyManagement中包含Spring Cloud设置。

<dependencyManagement> 
  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>  
      <artifactId>spring-cloud-dependencies</artifactId> 
      <version>Finchley.SR1</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

现在,我们可以使用经典的Spring Boot启动程序将依赖项添加到Feign:

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

Feign客户端使用声明方法来访问API。要使用它,我们必须首先在我们的Spring Boot应用程序上使用@EnableFeignClients注解启用S​​pring Cloud支持。

@SpringBootApplication
@EnableFeignClients 
public class FeignIntroductionApplication implements ApplicationRunner 
{ //omitted 
}

下一步是声明用于访问我们的API的接口。我们将其命名为KanbanClient,因为它将提供调用远程API的方法。

@FeignClient(name="KanbanClient"
             url=
"https://kanbanbackend.herokuapp.com/"
public interface KanbanClient { }

要将其转换为Feign客户端,我们必须在界面上设置@FeignClient注释,并为其指定名称属性,并使用url属性设置远程URL 。这里支持SpEL,因此我们可以将值外部化为属性文件。我们也可以使用Eureka在这里使用服务发现,而不是使用URL,如果使用Eureka服务发现,这里只要:

@FeignClient("KanbanApp")

KanbanApp是注册在Eureka服务注册器里面的应用名称,也就是对方生产者Srping.application.name=KanbanApp中配置的名称。

下面要定义远程调用的各个方法,不同远程API对应不同的接口方法,需要使用Spring MVC中的一些注释,这些注释通常也是用在REST服务器端的@Controller上。它们的行为相同,这里只是用在REST客户端。

POST
在方法上添加@PostMapping批注并在其中传递参数,将该方法转换为POST调用。在PostMapping注释中,我们提供了相对于在@FeignClient注释上设置的URL的端点(具体URL路径)。

@PostMapping(value = "/register")
String registerUser(User user);

用户是一个简单的POJO,带有用户名和密码字段。Feign,Spring会自动将其转换为JSON。

GET
原理与上面相同,但我们在方法上使用@GetMapping。我们还发送了身份验证标头。API使用X-Auth-Token。

@GetMapping("/boards")
List<Board> listBoards(
  @RequestHeader(
"X-Auth-Token"
  String authHeader
);

 /boards将返回用户的所有看板板的列表。Board是POJO,仅包含id和name。

PUT
同样,这次只需使用@PutMapping注释。

@PutMapping("/board/{id}")
Board changeBoard(
  @RequestHeader(
"X-Auth-Token") String authHeader, 
  @PathVariable(
"id") Long id, 
  Board board
);

我们可以通过将PUT提交看板的端点(/ board / {id})实现更改看板的名称。路径变量请参见下面的使用变量进行调用部分。

DELETE
只需要@DeleteMapping注释。

@DeleteMapping("/unregister")
ResponseEntity<Void> unregisterUser(
  @RequestHeader(
"X-Auth-Token") String authToken, 
  Confirmation user
);

此端点需要具有用户密码的Confirmation对象才能删除该帐户,并且如果成功则还需要返回200。


使用变量进行调用
如果我们的端点需要基于像ids这样的实体的变量,我们可以在方法参数上使用@PathVariable注释。它的行为与Spring MVC @Controllers相同。
然后可以在@PutMapping的端点声明中使用已定义的变量如:

@PutMapping("/board/{id}"
Board changeBoard(
  @RequestHeader(
"X-Auth-Token") String authHeader, 
  @PathVariable(
"id") Long id, 
  Board board
);

通过身份认证调用
我们将使用登录端点。它要求用户凭据作为基本身份验证发送,并将返回令牌以进行进一步身份验证。当我们成功调用/ login端点时,它将在响应头中返回auth令牌:

@PostMapping("/login")
ResponseEntity<Void> loginUser(
  @RequestHeader(
"Authorization") String authHeader
);

向下传递附加信息的第一种方法是在其上添加带有@RequestHeader注释的方法参数。参数的值将设置为注释中定义的HTTP标头的值。
在身份认证的情况下,它是Authorization标头。作为一个值,我们给它基本的auth编码字符串。
在随后的Kanban API调用中,我们将使用带有令牌的X-Auth-Token标头。
响应头不能作为方法返回值直接返回,但我们可以使用Spring的ResponseEntity,它是一个响应包装器。由于我们的端点不会在响应主体中返回任何内容,因此需要将Void作为参数化类型。
当在看板API中使用Spring Session时,需要通过X-Auth-Token标头交换auth令牌。
要检索我们调用的值:

String token = response.getHeaders().getFirst("X-Auth-Token");


其他认证方法
我们总是可以在每个方法上使用@RequestHeader注释传递身份验证标头。但是,还有一种在全局范围内指定的替代方法。
像Spring MVC一样,Feign有一个拦截器概念,可用于在远程调用之前执行特定的操作。入口点是RequestInterceptor接口。
使用Spring,我们只需要提供一个Bean来实现Spring上下文的特定接口,它将自动被使用。

@Bean 
AuthInterceptor authFeign() { 
  return new AuthInterceptor(); 
}
class AuthInterceptor implements RequestInterceptor { 
  @Override 
  public void apply(RequestTemplate template) { 
    template.header("Authorization", "<your token>"); 
  }
}

我们的拦截器是一个Spring Bean,因此我们可以使用Spring的强大功能并将authN信息外部化为属性,甚至可以从会话范围的bean中检索它,我们会根据每个用户来保存信息。

使用FeignClient
现在,我们可以像任何其他Spring Bean一样将KanbanClient注入我们的代码中。在启动时,Spring Cloud将为我们设置Feign客户端并为我们提供常规的Spring Proxy,以便我们可以简单地开始使用远程端。
我们使用Feign的客户端代码最终看起来像这样:

@FeignClient(name="KanbanClient"
             url=
"https://kanbanbackend.herokuapp.com/")
public interface KanbanClient {
  @PostMapping(value =
"/register"
  String registerUser(User user); 
  @DeleteMapping(
"/unregister")
  ResponseEntity<Void> unregisterUser(
    @RequestHeader(
"X-Auth-Token") String authToken, 
    Confirmation user
  );
  @PostMapping(
"/login"
  ResponseEntity<Void> loginUser(
    @RequestHeader(
"Authorization") String authHeader
  );
  @GetMapping(
"/boards")
  List<Board> listBoards(
    @RequestHeader(
"X-Auth-Token") String authHeader
  );
  @PostMapping(
"/boards"
  Board createBoard(
    @RequestHeader(
"X-Auth-Token") String authHeader,
    Board board
  );
  @PutMapping(
"/board/{id}")
  Board changeBoard(
    @RequestHeader(
"X-Auth-Token") String authHeader, 
    @PathVariable(
"id") Long id,
    Board board
  );
}

完整的源码在GitHub上