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