SpringBoot обновляет RestTemplateBuilder с 1.5.14 до 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

5 ответов

Решение

В приведенном ниже коде показано, как вам нужно создать шаблон для простых случаев.

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

Было бы лучше предоставить исходный код MyHttpComponentFactoryBuilderкласс. Но я предлагаю создать классMyHttpComponentFactory который расширяет SimpleClientHttpRequestFactory класс перенести свои коды из MyHttpComponentFactoryBuilder к нему.

Я написал подробные заметки на моей вики-странице github, убедитесь, что это будет полезно

Вот пример:

        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();
        }

Конструктор здесь больше не нужен, поскольку поставщик создает 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();
    }

Конечно, вы также можете использовать специализированный класс.

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();
 }

Попробуйте удалить .getClass()вызов, и если вызов.requestFactory указывает наrequestFactory(Class<? extends ClientHttpRequestFactory> requestFactory) метод класса RestTemplateBuilder затем, пожалуйста, поделитесь фрагментом кода вашего MyHttpComponentFactoryBuilder класс

Это должно работать (с использованием лямбды)

.requestFactory(() -> new MyHttpComponentFactoryBuilder().build())
Другие вопросы по тегам