SpringBoot 升级 RestTemplateBuilder 从 1.5.14 到 2.1.5

SpringBoot upgrade RestTemplateBuilder from 1.5.14 to 2.1.5

我的这段代码在使用 RestTemplateBuilder 1.5.14

的项目上运行良好
this.restTemplate = restTemplateBuilder
                .setConnectTimeout(connectTimeout)
                .setReadTimeout(readTimeout)
                .requestFactory(new MyHttpComponentFactoryBuilder()
                        .build())
                .build();

更新到RestTemplateBuilder 2.1.5后我有这段代码:

this.restTemplate = restTemplateBuilder
                .setConnectTimeout(Duration.ofMillis(connectTimeout))
                .setReadTimeout(Duration.ofMillis(readTimeout))
                .requestFactory(new MyHttpComponentFactoryBuilder().build().getClass())
                .build();

但是当 运行 代码时,我有一个 InvocationTargetException / NullPointerException 在删除行 .requestFactory(new MyHttpComponentFactoryBuilder().build().getClass()) 时消失,但调试 new MyHttpComponentFactoryBuilder().build().getClass() 不为空

我也尝试了建议的解决方案:

... 
.requestFactory(new MyRequestFactorySupplier())
...

class MyRequestFactorySupplier implements Supplier<ClientHttpRequestFactory> {

        @Override
        public ClientHttpRequestFactory get() {

            // Using Apache HTTP client.
            HttpClientBuilder clientBuilder = HttpClientBuilder.create();
            HttpClient httpClient = clientBuilder.build();
            HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
            requestFactory.setBufferRequestBody(false); // When sending large amounts of data via POST or PUT, it is recommended to change this property to false, so as not to run out of memory.
            return requestFactory;
        }

    }

但我也有 InvocationTargetException / NullPointerException

尝试删除 .getClass() 调用,如果 .requestFactory 调用 指向 class RestTemplateBuilderrequestFactory(Class<? extends ClientHttpRequestFactory> requestFactory) 方法,请分享您的 MyHttpComponentFactoryBuilder class

的代码片段

以下代码显示了您需要如何为简单案例创建模板。

RestTemplate tmpl = new RestTemplateBuilder().setConnectTimeout(Duration.ofMillis(200))
                                             .setReadTimeout(Duration.ofMillis(100))
                                             .requestFactory(org.springframework.http.client.SimpleClientHttpRequestFactory.class)
                                             .build();

最好能提供MyHttpComponentFactoryBuilderclass的源代码。但我的建议是创建一个扩展 SimpleClientHttpRequestFactory class 的 class MyHttpComponentFactory 将您的代码从 MyHttpComponentFactoryBuilder 迁移到它。

这应该有效(使用 lambda)

.requestFactory(() -> new MyHttpComponentFactoryBuilder().build())

您在这里不再需要构建器,因为供应商会按需构建 ClientHttpRequestFactory。将 RequestFactorySupplier 和 RestTemplateBuilder 定义为 beans。

    @Bean
    Supplier<ClientHttpRequestFactory> myRequestFactorySupplier() {
        return () -> {
            HttpClientBuilder clientBuilder = HttpClientBuilder.create();
            HttpClient httpClient = clientBuilder.build();
            HttpComponentsClientHttpRequestFactory requestFactory = 
                    new HttpComponentsClientHttpRequestFactory(httpClient);
            requestFactory.setConnectTimeout(5000);
            requestFactory.setReadTimeout(5000);
            requestFactory.setBufferRequestBody(false);
            return requestFactory;
        };
    }

    @Bean
    public RestTemplateBuilder restTemplateBuilder() {
        return new RestTemplateBuilder();
    }

像这样在控制器中使用工厂。

@RestController
public class TestController {

    private final RestTemplate restTemplate;

    public TestController(
            RestTemplateBuilder restTemplateBuilder,
            Supplier<ClientHttpRequestFactory> myRequestFactorySupplier
    ) {
            this.restTemplate = restTemplateBuilder                
                .requestFactory(myRequestFactorySupplier)
                .build();
    }

当然你也可以使用专门的 class.

public class MyRequestFactorySupplier implements Supplier<ClientHttpRequestFactory> {

        @Override
        public ClientHttpRequestFactory get() {
            // Using Apache HTTP client.
            HttpClientBuilder clientBuilder = HttpClientBuilder.create();
            HttpClient httpClient = clientBuilder.build();
            HttpComponentsClientHttpRequestFactory requestFactory = 
                    new HttpComponentsClientHttpRequestFactory(httpClient);
            requestFactory.setBufferRequestBody(false); // When sending large amounts of data via POST or PUT, it is recommended to change this property to false, so as not to run out of memory.
            return requestFactory;
        }

}

按照您的建议在控制器中使用它:

 public TestController(
     RestTemplateBuilder restTemplateBuilder,
     Supplier<ClientHttpRequestFactory> myRequestFactorySupplier
 ) {
     this.restTemplate = restTemplateBuilder
                .setConnectTimeout(Duration.ofMillis(5000))
                .setReadTimeout(Duration.ofMillis(5000))
                .requestFactory(new MyRequestFactorySupplier())
                .build();
 }

我在我的 github wiki 页面上写了详细的注释,请检查肯定会有帮助

示例如下:

        public String retrieveData(String id, String name) {

            HttpHeaders headers =createHeader();
            String requestJson = "{\"name\":\"" + name + "\"}";
            HttpEntity<String> request = new HttpEntity<String>(requestJson, headers);
            // external call time
            long startTime = System.currentTimeMillis();
            ResponseEntity<String> response = customRestTemplate().exchange(externalUrl, HttpMethod.POST, request,   
                    String.class);
            long endTime = System.currentTimeMillis();
            long duration = (endTime - startTime); // divide by 1000000 to get milliseconds.
            log.info("{\"RestTemplateDemo\":{\"id\":\"" + id + "\",\"external call duration\":" + duration + "}}");
            ObjectMapper mapper = new ObjectMapper();
            return response.getBody();
        }