11.6. 调用 REST 服务

Spring Boot 提供了各种便捷的方式来调用远程 REST 服务。如果您正在开发非阻塞反应式应用程序并且正在使用 Spring WebFlux,那么您可以使用WebClient. 如果您更喜欢阻止 API,那么您可以使用RestClientRestTemplate

11.6.1. WebClient

如果您的类路径上有 Spring WebFlux,我们建议您使用WebClient来调用远程 REST 服务。WebClient界面提供了函数式 API,并且是完全响应式的。您可以在 Spring 框架文档的WebClient专门部分了解更多相关信息。

如果您不编写响应式 Spring WebFlux 应用程序,则可以使用RestClient替代WebClient. 这提供了类似的功能 API,但是阻塞式的而不是响应式的。

Spring Boot为您创建并预配置原型WebClient.Builderbean。强烈建议将其注入您的组件中并使用它来创建WebClient实例。Spring Boot 正在配置该构建器以共享 HTTP 资源并以与服务器相同的方式反映编解码器设置(请参阅WebFlux HTTP 编解码器自动配置)等等。

下面的代码展示了一个典型的例子:

@Service
public class MyService {

    private final WebClient webClient;

    public MyService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.baseUrl("https://example.org").build();
    }

    public Mono<Details> someRestCall(String name) {
        return this.webClient.get().uri("/{name}/details", name).retrieve().bodyToMono(Details.class);
    }

}

WebClient运行时

Spring Boot 将根据应用程序类路径上可用的库自动检测使用哪个 ClientHttpConnector 来驱动WebClient。按照优先顺序,支持以下客户端:

  1. Reactor Netty

  2. Jetty RS 客户端

  3. Apache HttpClient

  4. JDK HttpClient

如果类路径上有多个客户端可用,则将使用最首选的客户端。

默认情况下,启动器spring-boot-starter-webflux依赖于io.projectreactor.netty:reactor-netty服务器和客户端实现。如果您选择使用 Jetty 作为反应式服务器,则应添加对 Jetty Reactive HTTP 客户端库 的依赖项org.eclipse.jetty:jetty-reactive-httpclient。服务器和客户端使用相同的技术有其优点,因为它将自动在客户端和服务器之间共享 HTTP 资源。

开发人员可以通过提供自定义ReactorResourceFactoryJettyResourceFactorybean来覆盖 Jetty 和 Reactor Netty 的资源配置- 这将应用于客户端和服务器。

如果您希望覆盖客户端的选择,您可以定义自己的ClientHttpConnectorbean 并完全控制客户端配置。

您可以在 Spring 框架WebClient参考文档中了解有关配置选项的更多信息。

WebClient定制

自定义有三种主要方法WebClient,具体取决于您希望自定义应用的范围。

为了使任何自定义的范围尽可能缩小,请注入自动配置的WebClient.Builder内容,然后根据需要调用其方法。 WebClient.Builder实例是有状态的:构建器上的任何更改都会反映在随后使用它创建的所有客户端中。如果您想使用同一个构建器创建多个客户端,您还可以考虑使用WebClient.Builder other = builder.clone();.

要对所有WebClient.Builder实例进行应用程序范围的附加自定义,您可以声明WebClientCustomizerbean 并在注入点位置更改WebClient.Builder

最后,您可以回退到原始 API 并使用WebClient.create(). 在这种情况下,不会应用任何WebClientCustomizer的自动配置。

WebClient SSL 支持

如果您需要在ClientHttpConnector所使用的WebClient上进行自定义 SSL 配置,您可以注入一个WebClientSsl可与构建器apply方法一起使用的实例。

该界面提供对您在application.propertiesapplication.yaml文件中定义的任何SSL 捆绑包的WebClientSsl访问。

下面的代码展示了一个典型的例子:

@Service
public class MyService {

    private final WebClient webClient;

    public MyService(WebClient.Builder webClientBuilder, WebClientSsl ssl) {
        this.webClient = webClientBuilder.baseUrl("https://example.org").apply(ssl.fromBundle("mybundle")).build();
    }

    public Mono<Details> someRestCall(String name) {
        return this.webClient.get().uri("/{name}/details", name).retrieve().bodyToMono(Details.class);
    }

}

11.6.2. Rest 客户端

如果您在应用程序中没有使用 Spring WebFlux 或 Project Reactor,我们建议您使用RestClient调用远程 REST 服务。

RestClient接口提供了函数式阻塞API。

Spring Boot为您创建并预配置原型RestClient.Builderbean。强烈建议将其注入您的组件中并使用它来创建RestClient实例。Spring Boot 正在使用HttpMessageConverters 和适当的 ClientHttpRequestFactory 配置该构建器。

下面的代码展示了一个典型的例子:

@Service
public class MyService {

    private final RestClient restClient;

    public MyService(RestClient.Builder restClientBuilder) {
        this.restClient = restClientBuilder.baseUrl("https://example.org").build();
    }

    public Details someRestCall(String name) {
        return this.restClient.get().uri("/{name}/details", name).retrieve().body(Details.class);
    }

}

RestClient定制

自定义有三种主要方法RestClient,具体取决于您希望自定义应用的范围。

为了使任何自定义的范围尽可能缩小,请注入自动配置的RestClient.Builder内容,然后根据需要调用其方法。

RestClient.Builder实例是有状态的:构建器上的任何更改都会反映在随后使用它创建的所有客户端中。如果您想使用同一个构建器创建多个客户端,您还可以考虑使用RestClient.Builder other = builder.clone();.

要对所有RestClient.Builder实例进行应用程序范围的附加自定义,您可以声明RestClientCustomizerbean 并在注入点位置更改RestClient.Builder

最后,您可以回退到原始 API 并使用RestClient.create(). 在这种情况下,不会应用任何RestClientCustomizer的自动配置。

RestClient SSL 支持

如果您需要在ClientHttpRequestFactory所使用的RestClient上进行自定义 SSL 配置,您可以注入一个RestClientSsl可与构建器apply方法一起使用的实例。

该界面提供对您在application.propertiesapplication.yaml文件中定义的任何SSL 捆绑包的RestClientSsl访问。

下面的代码展示了一个典型的例子:

@Service
public class MyService {

    private final RestClient restClient;

    public MyService(RestClient.Builder restClientBuilder, RestClientSsl ssl) {
        this.restClient = restClientBuilder.baseUrl("https://example.org").apply(ssl.fromBundle("mybundle")).build();
    }

    public Details someRestCall(String name) {
        return this.restClient.get().uri("/{name}/details", name).retrieve().body(Details.class);
    }

}

如果除了 SSL 捆绑包之外您还需要应用其他自定义,则可以将ClientHttpRequestFactorySettings类与ClientHttpRequestFactories一起使用:

@Service
public class MyService {

    private final RestClient restClient;

    public MyService(RestClient.Builder restClientBuilder, SslBundles sslBundles) {
        ClientHttpRequestFactorySettings settings = ClientHttpRequestFactorySettings.DEFAULTS
            .withReadTimeout(Duration.ofMinutes(2))
            .withSslBundle(sslBundles.getBundle("mybundle"));
        ClientHttpRequestFactory requestFactory = ClientHttpRequestFactories.get(settings);
        this.restClient = restClientBuilder.baseUrl("https://example.org").requestFactory(requestFactory).build();
    }

    public Details someRestCall(String name) {
        return this.restClient.get().uri("/{name}/details", name).retrieve().body(Details.class);
    }

}

11.6.3. RestTemplate

Spring Framework 的RestTemplate类早于RestClient并且是许多应用程序用来调用远程 REST 服务的经典方式。RestTemplate当您不想迁移到现有代码RestClient,或者因为您已经熟悉该API 时,您可能会选择使用RestTemplate

由于RestTemplate实例在使用之前通常需要进行自定义,因此 Spring Boot 不提供任何单个自动配置的RestTemplatebean。但是,它会自动配置 RestTemplateBuilder,可用于在需要时创建RestTemplate实例。自动配置RestTemplateBuilder可确保将合理HttpMessageConverters和适当的ClientHttpRequestFactory应用到RestTemplate实例。

下面的代码展示了一个典型的例子:

@Service
public class MyService {

    private final RestTemplate restTemplate;

    public MyService(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = restTemplateBuilder.build();
    }

    public Details someRestCall(String name) {
        return this.restTemplate.getForObject("/{name}/details", Details.class, name);
    }

}

RestTemplateBuilder包括许多有用的方法,可用于快速配置RestTemplate. 例如,要添加 BASIC 身份验证支持,您可以使用builder.basicAuthentication("user", "password").build().

RestTemplate定制

自定义有三种主要方法RestTemplate,具体取决于您希望自定义应用的范围。

为了使任何自定义的范围尽可能缩小,请注入自动配置的内容RestTemplateBuilder,然后根据需要调用其方法。每个方法调用都会返回一个新RestTemplateBuilder实例,因此自定义仅影响构建器的这种使用。

要进行应用程序范围的附加定制,请使用RestTemplateCustomizerbean。所有此类 bean 都会自动注册到自动配置RestTemplateBuilder,并应用于使用它构建的任何模板。

以下示例显示了一个定制程序,该定制程序为除以下主机192.168.0.5之外的所有主机配置代理的使用:

public class MyRestTemplateCustomizer implements RestTemplateCustomizer {

    @Override
    public void customize(RestTemplate restTemplate) {
        HttpRoutePlanner routePlanner = new CustomRoutePlanner(new HttpHost("proxy.example.com"));
        HttpClient httpClient = HttpClientBuilder.create().setRoutePlanner(routePlanner).build();
        restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
    }

    static class CustomRoutePlanner extends DefaultProxyRoutePlanner {

        CustomRoutePlanner(HttpHost proxy) {
            super(proxy);
        }

        @Override
        protected HttpHost determineProxy(HttpHost target, HttpContext context) throws HttpException {
            if (target.getHostName().equals("192.168.0.5")) {
                return null;
            }
            return super.determineProxy(target, context);
        }

    }

}

最后,您可以定义自己的RestTemplateBuilderbean。这样做将替换自动配置的构建器。如果您希望将任何RestTemplateCustomizerbean 应用于您的自定义构建器(就像自动配置一样),请使用RestTemplateBuilderConfigurer. 以下示例公开了与 Spring Boot 的自动配置将执行的操作相匹配的RestTemplateBuilder ,除此之外还指定了自定义连接和读取超时:

@Configuration(proxyBeanMethods = false)
public class MyRestTemplateBuilderConfiguration {

    @Bean
    public RestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer configurer) {
        return configurer.configure(new RestTemplateBuilder())
            .setConnectTimeout(Duration.ofSeconds(5))
            .setReadTimeout(Duration.ofSeconds(2));
    }

}

最极端(且很少使用)的选项是在不使用配置器的情况下创建您自己的RestTemplateBuilderbean。除了替换自动配置的构建器之外,这还可以防止使用任何RestTemplateCustomizer bean。

RestTemplate SSL 支持

如果您需要在 上进行自定义 SSL 配置RestTemplate,您可以将SSL 捆绑包应用于 RestTemplateBuilder,如本示例所示:

@Service
public class MyService {

    private final RestTemplate restTemplate;

    public MyService(RestTemplateBuilder restTemplateBuilder, SslBundles sslBundles) {
        this.restTemplate = restTemplateBuilder.setSslBundle(sslBundles.getBundle("mybundle")).build();
    }

    public Details someRestCall(String name) {
        return this.restTemplate.getForObject("/{name}/details", Details.class, name);
    }

}

11.6.4. RestClient 和 RestTemplate 的 HTTP 客户端检测

Spring Boot 将根据应用程序类路径上可用的库自动检测与 RestClientRestTemplate 一起使用的 HTTP 客户端。按照优先顺序,支持以下客户端:

  1. Apache HttpClient

  2. Jetty HttpClient

  3. OkHttp(已弃用)

  4. 简单的 JDK 客户端 ( HttpURLConnection)

如果类路径上有多个客户端可用,则将使用最首选的客户端。

最后更新于