51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

设置 Spring Cloud FeignClient 的目标 URL

1、简介 {#1简介}

在本文中,我们将学习如何给 Feign Client 接口设置目标 URL。

2、概览 {#2概览}

为了快速入门,我们将使用 JSONPlaceholder 网站中 Album(相册)、Post(帖子)和 Todo 对象的模拟响应。

Album 类如下:

public class Album {
private Integer id;
private Integer userId;
private String title;

// get、set 方法省略 }

Post 类如下:

public class Post {
private Integer id;
private Integer userId;
private String title;
private String body;

//get、set 方法省略

}

Todo 类如下:

public class Todo {
private Integer id;
private Integer userId;
private String title;
private Boolean completed;

// get、set 方法省略

}

3、在注解中添 Base URL {#3在注解中添-base-url}

我们可以在客户端接口的 @FeignClient 注解中的 url 属性中设置 base URL。然后,我们用相关 HTTP 动词注解方法,并添加所需的端点:

@FeignClient(name = "albumClient", url = "https://jsonplaceholder.typicode.com/albums/")
public interface AlbumClient {
@GetMapping(value = "/{id}")
Album getAlbumById(@PathVariable(value = "id") Integer id);

}

们添加一个 REST controller 来测试 client:

@RestController
public class ConfigureFeignUrlController {
private final AlbumClient albumClient;

// 省略构造方法

@GetMapping(value = "albums/{id}")
public Album getAlbumById(@PathVariable(value = "id") Integer id) {
    return albumClient.getAlbumById(id);
}

// 其他 controller 方法 }

如果目标 URL 在整个应用程序生命周期内都是静态的,则此选项非常有用。

4、使用配置属性 {#4使用配置属性}

另外,对于 Spring Cloud 版本 2022.0.1 或更高版本,我们可以在 application.properties 中设置 Feign 客户端接口的 URL。使用属性 spring.cloud.openfeign.client.config.<interface-name>.url 来实现。这里的 <interface-name> 是我们在 @FeignClient 注解中提供的 name 属性的值。

@FeignClient(name = "postClient")
public interface PostClient {
@GetMapping(value = &quot;/{id}&quot;)
Post getPostById(@PathVariable(value = &quot;id&quot;) Integer id);

}

application.properties 中添加 base URL:

spring.cloud.openfeign.client.config.postClient.url=https://jsonplaceholder.typicode.com/posts/

对于低于 2022.0.1 的 Spring Cloud 版本,我们可以为 @FeignClient 设置 url 取值表达式属性,以从 application.properties 中读取值:

@FeignClient(name = "postClient", url = "${spring.cloud.openfeign.client.config.postClient.url}")

接下来,让我们将该客户端注入到之前创建的 controller 中:

@RestController
public class FeignClientController {
    private final PostClient postClient;
// 其他属性 &amp; 构造函数

@GetMapping(value = &quot;posts/{id}&quot;)
public Post getPostById(@PathVariable(value = &quot;id&quot;) Integer id) {
    return postClient.getPostById(id);
}

// 其他 controller 方法 }

如果目标 URL 因应用程序的环境而异,则此选项会非常有用。例如,我们可能在开发环境中使用模拟服务器,而在生产环境中使用实际服务器。

5、使用 @RequestLine {#5使用-requestline}

Spring Cloud 提供了一种功能,我们可以在运行时覆盖目标 URL 或直接提供 URL。这是通过使用 @RequestLine 注解和使用 Feign Builder API 手动创建 feign 客户端来实现的:

@FeignClient(name = "todoClient")
public interface TodoClient {
@RequestLine(value = &quot;GET&quot;)
Todo getTodoById(URI uri);

}

我们需要在 controller 中手动创建这个 feign 客户端:

@RestController
@Import(FeignClientsConfiguration.class)
public class FeignClientController {
private final TodoClient todoClient;

// 其他属性

public FeignClientController(Decoder decoder, Encoder encoder) {
    this.todoClient = Feign.builder().encoder(encoder).decoder(decoder).target(Target.EmptyTarget.create(TodoClient.class));
    // 其他初始化操作

}

@GetMapping(value = &quot;todo/{id}&quot;)
public Todo getTodoById(@PathVariable(value = &quot;id&quot;) Integer id) {
    return todoClient.getTodoById(URI.create(&quot;https://jsonplaceholder.typicode.com/todos/&quot; + id));
}

// 其他 controller 方法

}

在这里,我们首先通过 FeignClientsConfiguration.class 导入默认的 feign 客户端配置。Feign.Builder 用于自定义 API 接口的这些属性。我们可以配置 encoderdecoderconnectTimeoutreadTimeoutauthentication 等属性。

target 属性定义了这些属性将应用于哪个接口。该接口有两种实现方式: EmptyTargetHardCodedTargetEmptyTarget 类在编译时不需要 URL,而 HardCodedTarget 则需要。

注意,作为参数提供的 URI 参数将覆盖 @FeignClient 注解中提供的 URL 和配置属性中的 URL。同样地,@FeignClient 注解中提供的 URL 将覆盖 properties 文件中提供的 URL。

6、使用 RequestInterceptor {#6使用-requestinterceptor}

在运行时提供目标 URL 的另一种方法是向 Feign.Builder 提供自定义 RequestInterceptor。在这里,我们将覆盖 RestTemplatetarget 属性,将 URL 更新为通过 requestInterceptor 提供给 Feign.Builder 的 URL:

public class DynamicUrlInterceptor implements RequestInterceptor {
    private final Supplier<String> urlSupplier;
    // 构造器省略
@Override
public void apply(RequestTemplate template) {
    String url = urlSupplier.get();
    if (url != null) {
        template.target(url);
    }
}

}

AlbumClient.java 中添加另一个方法:

@GetMapping(value = "/{id}")
Album getAlbumByIdAndDynamicUrl(@PathVariable(name = "id") Integer id);

我们要在 ConfigureFeignUrlController 的方法中使用 Builder 来创建 AlbumClient 的实例,而不是在构造函数中使用 Builder

@RestController
@Import(FeignClientsConfiguration.class)
public class ConfigureFeignUrlController {
private final ObjectFactory&lt;HttpMessageConverters&gt; messageConverters;

private final ObjectProvider&lt;HttpMessageConverterCustomizer&gt; customizers;

// 省略其他属性,构造函数和 controller 方法

@GetMapping(value = &quot;/dynamicAlbums/{id}&quot;)
public Album getAlbumByIdAndDynamicUrl(@PathVariable(value = &quot;id&quot;) Integer id) {
    AlbumClient client = Feign.builder()
      .requestInterceptor(new DynamicUrlInterceptor(() -&gt; &quot;https://jsonplaceholder.typicode.com/albums/&quot;))
      .contract(new SpringMvcContract())
      .encoder(new SpringEncoder(messageConverters))
      .decoder(new SpringDecoder(messageConverters, customizers))
      .target(Target.EmptyTarget.create(AlbumClient.class));
 
    return client.getAlbumByIdAndDynamicUrl(id);
}

}

在这里,我们添加了上文创建的 DynamicUrlInterceptor,它可接受 URL 以覆盖 AlbumClient 的默认 URL。我们还配置客户端使用 SpringMvcContractSpringEncoderSpringDecoder

当我们需要在应用程序中为 Webhook 提供支持时,后两个选项将非常有用,因为每个客户端的目标 URL 都会不同。

7、总结 {#7总结}

在本文中,我们学习了如何以不同方式配置 Feign Client 接口的目标 URL。


参考:https://www.baeldung.com/spring-cloud-feignclient-url

赞(6)
未经允许不得转载:工具盒子 » 设置 Spring Cloud FeignClient 的目标 URL