摘要:后端服务开发一般会远程调用第三方接口,Spring Boot也整合了远程REST服务调用方式。开发人员可以通过自定义配置定义RestTemplate类和WebClient类,从而进行第三方接口调用操作。
后端服务开发一般会远程调用第三方接口,Spring Boot也整合了远程REST服务调用方式。开发人员可以通过自定义配置定义RestTemplate类和WebClient类,从而进行第三方接口调用操作。
由于Spring Boot不提供RestTemplate自动配置,因此可以使用RestTemplate-Builder来创建RestTemplate实例,代码如下:
@Service
public class MyService {
private final RestTemplate restTemplate;
public MyService(RestTemplateBuilder restTemplateBuilder)
{
//创建RestTemplate
this.restTemplate = restTemplateBuilder.build;
}
public Details someRestCall(String name) {
//请求调用
return
this.restTemplate.getForObject("/{name}/details",
Details.class, name);
}
}
还可以通过自定义SimpleClientHttpRequestFactory的方式创建RestTemplate,代码如下:
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate
restTemplate(ClientHttpRequestFactory factory) {
return new RestTemplate(factory); //创建
RestTemplate
}
@Bean
public ClientHttpRequestFactory
simpleClientHttpRequestFactory {
SimpleClientHttpRequestFactory factory = new
SimpleClient
HttpRequestFactory;
factory.setConnectTimeout(15000); //设置
连接超时
factory.setReadTimeout(5000); //设置
读取超时
return factory;
}
}
Spring框架从5.0开始引入了WebFlux,如果是WebFlux工程,可以使用WebClient类进行远程REST服务调用。相比RestTemplate,WebClient的功能更多,并且是纯异步交互的。在Spring Boot中推荐使用WebClient.Builder新建WebClient实例。
改造4.4.1节中的例子,代码如下:
@Service
public class MyService {
private final WebClient webClient;
public MyService(WebClient.Builder webClientBuilder) {
//创建WebClient
this.webClient =
webClientBuilder.baseUrl("https://example.
org").build;
}
public Mono someRestCall(String name) {
//通过WebClient进行调用
return this.webClient.get.uri("/{name}/details",
name)
.retrieve.bodyToMono(Details.class);
}
}
通过自定义生成WebClient,代码如下:
//自定义WebClient
@Data
@Configuration
@ConditionalOnProperty(name = "httpClient.connect.timeout")
public class WebClientConfig {
@Value("${HttpClient.connect.timeout:2000}")
private int connectTimeOut;
@Value("${httpClient.read.timeout:2000}")
private int readTimeOut;
@Value("${httpClient.write.timeout:2000}")
private int writeTimeout;
@Value("${httpClient.retry.times:2}")
private int retryTimes;
@Value("${httpClient.connpool.maxConns:16}")
private int maxConns;
@Value("${httpClient.connpool.workCounts:16}")
private int workCounts;
@Value("${httpClient.connpool.acquireTimeOut:1000}")
private int acquireTimeOut;
//声明ReactorResourceFactory
@Bean
@Primary
public ReactorResourceFactory resourceFactory {
ReactorResourceFactory factory = new
ReactorResourceFactory;
factory.setUseGlobalResources(false);
factory.setConnectionProvider(ConnectionProvider.builder
("httpClient").metrics(true).maxConnections(maxConns)
.pendingAcquireTimeout(Duration.ofMillis(acquireTimeOut)).
build);
factory.setLoopResources(LoopResources.create("httpClient",
workCounts, true));
return factory;
}
//定义Retry策略
@Bean
@Primary
@RefreshScope
public Retry retry {
return Retry.anyOf(ReadTimeoutException.class,
ConnectTimeout
Exception.class, WebClientResponseException.class)
.fixedBackoff(Duration.ZERO)
.retryMax(retryTimes)
//retry次数
.doOnRetry((exception) -> {
//异常日志
log.warn("Retried ,Exception is {}" +
exception);
});
}
//定义WebClient
@Bean
@Primary
@RefreshScope
public WebClient webClient(WebClient.Builder
builder,Reactor
ResourceFactory resourceFactory) {
Function mapper = client ->
client.tcpConfiguration(tcpClient ->
tcpClient.option(ChannelOption.CONNECT_TIMEOUT_
MILLIS, connectTimeOut)
//创建连接超时时间
.option(ChannelOption.TCP_NODELAY, true)
//连接策略
.doOnConnected(connection ->
{
connection.addHandlerLast(new Read
TimeoutHandler(readTimeOut, TimeUnit.MILLISECONDS));
connection.addHandlerLast(new Write
TimeoutHandler(writeTimeout, TimeUnit.MILLISECONDS));
}))
.headers(headerBuilder -> { //设置
header属性
headerBuilder.set("Accept
charset", "utf-8");
Encoding", "gzip,
x-gzip, deflate");
headerBuilder.set("ContentType",
"text/plain;
charset=utf-8");
}).keepAlive(true);
ClientHttpConnector connector = new
ReactorClientHttpConnector
(resourceFactory, mapper);
return builder.clientConnector(connector).build;
}
}
来源:大数据架构师