RestTemplate не работает в Spring Boot 3. Я перехожу с Spring Boot 2.x на 3.x.
У меня RestTemplate настроен для взаимодействия с двумя службами, но, поскольку это режим обслуживания, можем ли мы использовать RestTemplate в Spring Boot 3?
Одна из реализаций, конечная точка, настроенная через RestTemplate, не работает. Я не могу обмениваться данными между службами.
Здесь я получаю эту ошибку:
java.lang.IllegalArgumentException: Service Instance cannot be null
at org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient.execute(BlockingLoadBalancerClient.java:98)
Многие блоги предлагали использовать WebClient вместо RestTemplate.
Это мой класс конфигурации. Когда я удаляю эту аннотацию, операция RestTemplate работает нормально, но в моем случае мне нужно иметь
@Configuration
@Slf4j
@Data
public class RestTemplateConfigLoadBalanced {
private static final int FIX_DELAY = 10000;
private final RestTemplateConfigProperties loadBalancedProperties;
@Value("${discovery.port:8080}")
private Integer discoveryPort;
@LoadBalanced
@Bean(name = "loadBalancedClient")
public RestTemplate restTemplate(OutboundRequestIdAppender outboundRequestIdAppender,
RestTemplateRequestLogger outboundRequestLogger) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory1());
List<ClientHttpRequestInterceptor> interceptors = restTemplate.getInterceptors();
interceptors.add(outboundRequestIdAppender);
interceptors.add(outboundRequestLogger);
restTemplate.setInterceptors(interceptors);
return restTemplate;
}
@Bean
public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory1() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setHttpClient(httpClient1());
return clientHttpRequestFactory;
}
@Bean
public CloseableHttpClient httpClient1() throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
org.apache.hc.client5.http.config.RequestConfig requestConfig = RequestConfig.custom()
.setConnectionRequestTimeout(Timeout.ofDays(loadBalancedProperties.getRequestTimeout()))
.setConnectionRequestTimeout(Timeout.ofDays(loadBalancedProperties.getConnectTimeout()))
.setResponseTimeout(Timeout.ofDays(loadBalancedProperties.getSocketTimeout()))
.build();
SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(new TrustSelfSignedStrategy())
.build();
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, org.apache.hc.client5.http.ssl.NoopHostnameVerifier.INSTANCE);
Duration evictIdleDuration = Duration.of(loadBalancedProperties.getEvictIdleConnectionsIdleTime(), ChronoUnit.DAYS);
long evictIdleMilliseconds = evictIdleDuration.toMillis();
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactory)
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
HttpRequestRetryStrategy customRetryStrategy = new HttpRequestRetryStrategy() {
@Override
public boolean retryRequest(HttpRequest httpRequest, IOException e, int executionCount, HttpContext httpContext) {
return retryHttpRequest(executionCount);
}
@Override
public boolean retryRequest(HttpResponse httpResponse, int i, HttpContext httpContext) {
return false;
}
@Override
public TimeValue getRetryInterval(HttpResponse httpResponse, int i, HttpContext httpContext) {
return null;
}
};
return HttpClients.custom()
.setSchemePortResolver(new SchemePortResolver() {
@Override
public int resolve(org.apache.hc.core5.http.HttpHost httpHost) {
return discoveryPort;
}
})
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.evictIdleConnections(TimeValue.ofMilliseconds(evictIdleMilliseconds))
.evictExpiredConnections()
.setKeepAliveStrategy(connectionKeepAliveStrategy1())
// .setRetryStrategy((exception, executionCount, context) -> retryHttpRequest(executionCount))
.setRetryStrategy(customRetryStrategy)
.build();
}
@Bean(name = "loadbalancePoolingConnectionManager")
public org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager poolingConnectionManager1() {
return getPoolingHttpClientConnectionManager(log, loadBalancedProperties.getMaxTotalConnections(), loadBalancedProperties.getMaxRoutePerHost());
}
@Bean
public ConnectionKeepAliveStrategy connectionKeepAliveStrategy1() {
return (response, context) -> TimeValue.ofDays(determineConnectionKeepAliveTime(response));
}
@Bean
public Runnable idleConnectionMonitor(@Qualifier("loadbalancePoolingConnectionManager") final PoolingHttpClientConnectionManager connectionManager) {
return getRunnable(connectionManager, log, loadBalancedProperties.getCloseIdleConnectionWaitTimeSecs());
}
public long determineConnectionKeepAliveTime(HttpResponse response) {
return getConnectionKeepAliveTime(response, loadBalancedProperties.getDefaultKeepAliveTimeMillis());
}
static long getConnectionKeepAliveTime(HttpResponse response, int defaultKeepAliveTimeMillis) {
BasicHeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.next();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase("timeout")) {
return Long.parseLong(value) * 1000;
}
}
return defaultKeepAliveTimeMillis;
}
static Runnable getRunnable(PoolingHttpClientConnectionManager connectionManager, Logger log, int closeIdleConnectionWaitTimeSecs) {
return new Runnable() {
@Override
@Scheduled(fixedDelay = FIX_DELAY)
public void run() {
if (connectionManager != null) {
log.trace("run IdleConnectionMonitor - Closing expired and idle connections...");
connectionManager.closeExpired();
connectionManager.closeIdle(TimeValue.ofDays(closeIdleConnectionWaitTimeSecs));
} else {
log.trace("run IdleConnectionMonitor - Http Client Connection manager is not initialised");
}
}
};
}
static PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager(Logger log, int maxTotalConnections, int maxRoutePerHost) {
SSLContextBuilder builder = new SSLContextBuilder();
try {
builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
} catch (NoSuchAlgorithmException | KeyStoreException e) {
log.warn("Exception occurred while building SSL context", e);
}
SSLConnectionSocketFactory sslsf = null;
try {
sslsf = new SSLConnectionSocketFactory(builder.build());
} catch (KeyManagementException | NoSuchAlgorithmException e) {
log.warn("Exception occurred while creating SSL connection socket factory", e);
}
assert sslsf != null;
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
.<ConnectionSocketFactory>create().register("https", sslsf)
.register("http", new PlainConnectionSocketFactory())
.build();
PoolingHttpClientConnectionManager poolingConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
poolingConnectionManager.setMaxTotal(maxTotalConnections);
poolingConnectionManager.setDefaultMaxPerRoute(maxRoutePerHost);
return poolingConnectionManager;
}
public boolean retryHttpRequest(int executionCount) {
if (executionCount > loadBalancedProperties.getMaxExecutionCount()) {
log.warn("Maximum retries {} reached", loadBalancedProperties.getMaxExecutionCount());
return false;
}
log.warn("Retry http request. Retry Count: {}", executionCount);
return true;
}
}