返回介绍

4.4 远程调用

发布于 2025-04-21 20:58:44 字数 5249 浏览 0 评论 0 收藏

后端服务开发一般会远程调用第三方接口,Spring Boot 也整合了远程 REST 服务调用方式。开发人员可以通过自定义配置定义 RestTemplate 类和 WebClient 类,从而进行第三方接口调用操作。

4.4.1 调用 RestTemplate

由于 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;
        }
}

4.4.2 调用 WebClient

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<Details> 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<HttpClient, HttpClient> 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");
                            headerBuilder.set("Accept-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();
    }
}

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。