REST サービスの呼び出し
Spring Boot は、リモート REST サービスを呼び出すためのさまざまな便利な方法を提供します。ノンブロッキングのリアクティブアプリケーションを開発していて、Spring WebFlux を使用している場合は、WebClient
を使用できます。API をブロックしたい場合は、RestClient
または RestTemplate
を使用できます。
WebClient
クラスパスに Spring WebFlux がある場合は、WebClient
を使用して リモート REST サービスを呼び出すことをお勧めします。WebClient
インターフェースは関数型 API を提供し、完全にリアクティブです。WebClient
の詳細については、Spring Framework ドキュメントの専用セクションを参照してください。
リアクティブ Spring WebFlux アプリケーションを作成していない場合は、WebClient の代わりに RestClient を使用できます。これは同様の機能の API を提供しますが、リアクティブではなくブロッキングです。 |
Spring Boot は、プロトタイプ WebClient.Builder
Bean を作成し、事前構成します。これをコンポーネントに挿入し、それを使用して WebClient
インスタンスを作成することを強くお勧めします。Spring Boot は、HTTP リソースを共有し、サーバーのものと同じ方法でコーデックのセットアップを反映するようにそのビルダーを構成しています (WebFlux HTTP コーデックの自動構成を参照)。
次のコードは典型的な例を示しています。
Java
Kotlin
import reactor.core.publisher.Mono;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
@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);
}
}
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.WebClient
import reactor.core.publisher.Mono
@Service
class MyService(webClientBuilder: WebClient.Builder) {
private val webClient: WebClient
init {
webClient = webClientBuilder.baseUrl("https://example.org").build()
}
fun someRestCall(name: String?): Mono<Details> {
return webClient.get().uri("/{name}/details", name)
.retrieve().bodyToMono(Details::class.java)
}
}
WebClient ランタイム
Spring Boot は、アプリケーションのクラスパスで利用可能なライブラリに応じて、WebClient
の駆動にどの ClientHttpConnector
を使用するかを自動検出します。優先順位に従って、次のクライアントがサポートされます。
Reactor Netty
Jetty RS クライアント
Apache HttpClient
JDK HttpClient
クラスパス上で複数のクライアントが使用可能な場合は、最も優先されるクライアントが使用されます。
spring-boot-starter-webflux
スターターは、デフォルトで io.projectreactor.netty:reactor-netty
に依存しており、サーバーとクライアントの両方の実装をもたらします。代わりにリアクティブサーバーとして Jetty を使用することを選択した場合は、Jetty リアクティブ HTTP クライアントライブラリ org.eclipse.jetty:jetty-reactive-httpclient
への依存関係を追加する必要があります。サーバーとクライアントに同じテクノロジーを使用すると、クライアントとサーバー間で HTTP リソースが自動的に共有されるため、利点があります。
開発者は、カスタム ReactorResourceFactory
または JettyResourceFactory
Bean を提供することにより、Jetty および Reactor Netty のリソース構成をオーバーライドできます。これは、クライアントとサーバーの両方に適用されます。
クライアントのその選択をオーバーライドする場合は、独自の ClientHttpConnector
Bean を定義し、クライアント構成を完全に制御できます。
Spring Framework リファレンスドキュメントの WebClient
構成オプションについて詳しく知ることができます。
WebClient のカスタマイズ
WebClient
カスタマイズには、カスタマイズの適用範囲に応じて 3 つの主なアプローチがあります。
カスタマイズの範囲をできる限り狭くするには、自動構成された WebClient.Builder
を挿入し、必要に応じてそのメソッドを呼び出します。WebClient.Builder
インスタンスはステートフルです: ビルダーでの変更は、その後作成されたすべてのクライアントに反映されます。同じビルダーで複数のクライアントを作成する場合は、WebClient.Builder other = builder.clone();
でビルダーを複製することも検討できます。
アプリケーション全体で、すべての WebClient.Builder
インスタンスに追加のカスタマイズを行うには、WebClientCustomizer
Bean を宣言し、注入の時点で WebClient.Builder
をローカルに変更します。
最後に、元の API にフォールバックして WebClient.create()
を使用できます。その場合、自動構成または WebClientCustomizer
は適用されません。
WebClient SSL サポート
WebClient
で使用される ClientHttpConnector
でカスタム SSL 構成が必要な場合は、ビルダーの apply
メソッドで使用できる WebClientSsl
インスタンスを挿入できます。
WebClientSsl
インターフェースは、application.properties
または application.yaml
ファイルで定義した任意の SSL バンドルへのアクセスを提供します。
次のコードは典型的な例を示しています。
Java
Kotlin
import reactor.core.publisher.Mono;
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
@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);
}
}
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientSsl
import org.springframework.stereotype.Service
import org.springframework.web.reactive.function.client.WebClient
import reactor.core.publisher.Mono
@Service
class MyService(webClientBuilder: WebClient.Builder, ssl: WebClientSsl) {
private val webClient: WebClient
init {
webClient = webClientBuilder.baseUrl("https://example.org")
.apply(ssl.fromBundle("mybundle")).build()
}
fun someRestCall(name: String?): Mono<Details> {
return webClient.get().uri("/{name}/details", name)
.retrieve().bodyToMono(Details::class.java)
}
}
RestClient
アプリケーションで Spring WebFlux またはプロジェクト Reactor を使用していない場合は、RestClient
を使用して リモート REST サービスを呼び出すことをお勧めします。
RestClient
インターフェースは、関数型スタイルのブロッキング API を提供します。
Spring Boot は、プロトタイプ RestClient.Builder
Bean を作成し、事前構成します。これをコンポーネントに挿入し、それを使用して RestClient
インスタンスを作成することを強くお勧めします。Spring Boot は、そのビルダーを HttpMessageConverters
および適切な ClientHttpRequestFactory
で構成しています。
次のコードは典型的な例を示しています。
Java
Kotlin
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@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);
}
}
import org.springframework.boot.docs.io.restclient.restclient.ssl.Details
import org.springframework.stereotype.Service
import org.springframework.web.client.RestClient
@Service
class MyService(restClientBuilder: RestClient.Builder) {
private val restClient: RestClient
init {
restClient = restClientBuilder.baseUrl("https://example.org").build()
}
fun someRestCall(name: String?): Details {
return restClient.get().uri("/{name}/details", name)
.retrieve().body(Details::class.java)!!
}
}
RestClient のカスタマイズ
RestClient
カスタマイズには、カスタマイズの適用範囲に応じて 3 つの主なアプローチがあります。
カスタマイズの範囲をできる限り狭くするには、自動構成された RestClient.Builder
を挿入し、必要に応じてそのメソッドを呼び出します。RestClient.Builder
インスタンスはステートフルです: ビルダーでの変更は、その後作成されたすべてのクライアントに反映されます。同じビルダーで複数のクライアントを作成する場合は、RestClient.Builder other = builder.clone();
でビルダーを複製することも検討できます。
アプリケーション全体で、すべての RestClient.Builder
インスタンスに追加のカスタマイズを行うには、RestClientCustomizer
Bean を宣言し、注入の時点で RestClient.Builder
をローカルに変更します。
最後に、元の API にフォールバックして RestClient.create()
を使用できます。その場合、自動構成または RestClientCustomizer
は適用されません。
RestClient SSL サポート
RestClient
で使用される ClientHttpRequestFactory
でカスタム SSL 構成が必要な場合は、ビルダーの apply
メソッドで使用できる RestClientSsl
インスタンスを挿入できます。
RestClientSsl
インターフェースは、application.properties
または application.yaml
ファイルで定義した任意の SSL バンドルへのアクセスを提供します。
次のコードは典型的な例を示しています。
Java
Kotlin
import org.springframework.boot.autoconfigure.web.client.RestClientSsl;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@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);
}
}
import org.springframework.boot.autoconfigure.web.client.RestClientSsl
import org.springframework.boot.docs.io.restclient.restclient.ssl.settings.Details
import org.springframework.stereotype.Service
import org.springframework.web.client.RestClient
@Service
class MyService(restClientBuilder: RestClient.Builder, ssl: RestClientSsl) {
private val restClient: RestClient
init {
restClient = restClientBuilder.baseUrl("https://example.org")
.apply(ssl.fromBundle("mybundle")).build()
}
fun someRestCall(name: String?): Details {
return restClient.get().uri("/{name}/details", name)
.retrieve().body(Details::class.java)!!
}
}
SSL バンドルに加えて他のカスタマイズを適用する必要がある場合は、ClientHttpRequestFactorySettings
クラスを ClientHttpRequestFactories
とともに使用できます。
Java
Kotlin
import java.time.Duration;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.client.ClientHttpRequestFactories;
import org.springframework.boot.web.client.ClientHttpRequestFactorySettings;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestClient;
@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);
}
}
import org.springframework.boot.ssl.SslBundles
import org.springframework.boot.web.client.ClientHttpRequestFactories
import org.springframework.boot.web.client.ClientHttpRequestFactorySettings
import org.springframework.stereotype.Service
import org.springframework.web.client.RestClient
import java.time.Duration
@Service
class MyService(restClientBuilder: RestClient.Builder, sslBundles: SslBundles) {
private val restClient: RestClient
init {
val settings = ClientHttpRequestFactorySettings.DEFAULTS
.withReadTimeout(Duration.ofMinutes(2))
.withSslBundle(sslBundles.getBundle("mybundle"))
val requestFactory = ClientHttpRequestFactories.get(settings)
restClient = restClientBuilder
.baseUrl("https://example.org")
.requestFactory(requestFactory).build()
}
fun someRestCall(name: String?): Details {
return restClient.get().uri("/{name}/details", name).retrieve().body(Details::class.java)!!
}
}
RestTemplate
Spring Framework の RestTemplate
(Javadoc) クラスは RestClient
よりも前から存在し、多くのアプリケーションが リモート REST サービスを呼び出すために使用する典型的な方法です。RestClient
に移行したくない既存のコードがある場合、または RestTemplate
API にすでに慣れている場合は、RestTemplate
の使用を選択することもできます。
RestTemplate
インスタンスは使用前にカスタマイズする必要があることが多いため、Spring Boot には単一の自動構成 RestTemplate
Bean が提供されていません。ただし、RestTemplateBuilder
は自動構成され、必要に応じて RestTemplate
インスタンスの作成に使用できます。自動構成された RestTemplateBuilder
により、適切な HttpMessageConverters
と適切な ClientHttpRequestFactory
が RestTemplate
インスタンスに適用されます。
次のコードは典型的な例を示しています。
Java
Kotlin
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.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);
}
}
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
@Service
class MyService(restTemplateBuilder: RestTemplateBuilder) {
private val restTemplate: RestTemplate
init {
restTemplate = restTemplateBuilder.build()
}
fun someRestCall(name: String): Details {
return restTemplate.getForObject("/{name}/details", Details::class.java, name)!!
}
}
RestTemplateBuilder
には、RestTemplate
を迅速に構成するために使用できる便利なメソッドが多数含まれています。例: BASIC 認証サポートを追加するには、builder.basicAuthentication("user", "password").build()
を使用できます。
RestTemplate のカスタマイズ
RestTemplate
カスタマイズには、カスタマイズの適用範囲に応じて 3 つの主なアプローチがあります。
カスタマイズの範囲をできる限り狭くするには、自動構成された RestTemplateBuilder
を挿入し、必要に応じてそのメソッドを呼び出します。各メソッド呼び出しは新しい RestTemplateBuilder
インスタンスを返すため、カスタマイズはこのビルダーの使用にのみ影響します。
アプリケーション全体で追加のカスタマイズを行うには、RestTemplateCustomizer
Bean を使用します。このような Bean はすべて、自動構成された RestTemplateBuilder
に自動的に登録され、それを使用して作成されたすべてのテンプレートに適用されます。
次の例は、192.168.0.5
を除くすべてのホストに対してプロキシの使用を構成するカスタマイザーを示しています。
Java
Kotlin
import org.apache.hc.client5.http.classic.HttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;
import org.apache.hc.client5.http.routing.HttpRoutePlanner;
import org.apache.hc.core5.http.HttpException;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.springframework.boot.web.client.RestTemplateCustomizer;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
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);
}
}
}
import org.apache.hc.client5.http.classic.HttpClient
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner
import org.apache.hc.client5.http.routing.HttpRoutePlanner
import org.apache.hc.core5.http.HttpException
import org.apache.hc.core5.http.HttpHost
import org.apache.hc.core5.http.protocol.HttpContext
import org.springframework.boot.web.client.RestTemplateCustomizer
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory
import org.springframework.web.client.RestTemplate
class MyRestTemplateCustomizer : RestTemplateCustomizer {
override fun customize(restTemplate: RestTemplate) {
val routePlanner: HttpRoutePlanner = CustomRoutePlanner(HttpHost("proxy.example.com"))
val httpClient: HttpClient = HttpClientBuilder.create().setRoutePlanner(routePlanner).build()
restTemplate.requestFactory = HttpComponentsClientHttpRequestFactory(httpClient)
}
internal class CustomRoutePlanner(proxy: HttpHost?) : DefaultProxyRoutePlanner(proxy) {
@Throws(HttpException::class)
public override fun determineProxy(target: HttpHost, context: HttpContext): HttpHost? {
if (target.hostName == "192.168.0.5") {
return null
}
return super.determineProxy(target, context)
}
}
}
最後に、独自の RestTemplateBuilder
Bean を定義できます。そうすることで、自動構成されたビルダーが置き換えられます。自動構成の場合と同様に、RestTemplateCustomizer
Bean をカスタムビルダーに適用する場合は、RestTemplateBuilderConfigurer
を使用して構成します。次の例では、カスタム接続と読み取りのタイムアウトも指定されていることを除いて、Spring Boot の自動構成が実行したものと一致する RestTemplateBuilder
を公開しています。
Java
Kotlin
import java.time.Duration;
import org.springframework.boot.autoconfigure.web.client.RestTemplateBuilderConfigurer;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@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));
}
}
import org.springframework.boot.autoconfigure.web.client.RestTemplateBuilderConfigurer
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import java.time.Duration
@Configuration(proxyBeanMethods = false)
class MyRestTemplateBuilderConfiguration {
@Bean
fun restTemplateBuilder(configurer: RestTemplateBuilderConfigurer): RestTemplateBuilder {
return configurer.configure(RestTemplateBuilder()).setConnectTimeout(Duration.ofSeconds(5))
.setReadTimeout(Duration.ofSeconds(2))
}
}
最も極端な(そしてめったに使用されない)オプションは、コンフィギュレーターを使用せずに独自の RestTemplateBuilder
Bean を作成することです。自動構成されたビルダーを置き換えるだけでなく、これにより RestTemplateCustomizer
Bean が使用されなくなります。
RestTemplate SSL サポート
RestTemplate
でカスタム SSL 構成が必要な場合は、次の例に示すように SSL バンドルを RestTemplateBuilder
に適用できます。
Java
Kotlin
import org.springframework.boot.docs.io.restclient.resttemplate.Details;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@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);
}
}
import org.springframework.boot.docs.io.restclient.resttemplate.Details
import org.springframework.boot.ssl.SslBundles
import org.springframework.boot.web.client.RestTemplateBuilder
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
@Service
class MyService(restTemplateBuilder: RestTemplateBuilder, sslBundles: SslBundles) {
private val restTemplate: RestTemplate
init {
restTemplate = restTemplateBuilder.setSslBundle(sslBundles.getBundle("mybundle")).build()
}
fun someRestCall(name: String): Details {
return restTemplate.getForObject("/{name}/details", Details::class.java, name)!!
}
}
RestClient および RestTemplate の HTTP クライアントの検出
Spring Boot は、アプリケーションのクラスパスで使用可能なライブラリに応じて、RestClient
および RestTemplate
で使用する HTTP クライアントを自動検出します。優先順位に従って、次のクライアントがサポートされます。
Apache HttpClient
Jetty HttpClient
OkHttp (非推奨)
シンプルな JDK クライアント (
HttpURLConnection
)
クラスパス上で複数のクライアントが使用可能な場合は、最も優先されるクライアントが使用されます。