2

We do have following Configuration to build Spring beans.

Built configuration beans in Spring Beans with Connection Pool manager and ClosableHttpClient.

RestClient class autowires RestTemplate objects to make post calls.

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.ResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import java.time.Duration;
import java.util.List;

@Configuration
@Data
@Slf4j
public class ApplicationConfig {

    @Value("${nexus.security.enabled}")
    private boolean securityEnabled;

    @Value("${nexus.security.ignored}")
    private List<String> securityIgnoredList;

    @Value("${external.card.readTimeoutInMillis}")
    private int readTimeoutInMillis;

    @Value("${external.card.connectionTimeoutInMillis}")
    private int connectionTimeoutInMillis;

    @Value("${external.card.connectionRequestTimeoutInMillis}")
    private int connectionRequestTimeoutInMillis;

    @Value("${external.card.maxTotalConnections}")
    private int maxTotalConnections;

    @Value("${external.card.defaultMaxPerRoute}")
    private int defaultMaxPerRoute;

    @Bean
    @Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT)
    public PoolingHttpClientConnectionManager poolingHttpClientConnectionManager()
    {
        log.info("PoolingHttpClientConnectionManager Build for {}", ConfigConstants.CONFIG_NAME_DEFAULT);
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
        poolingHttpClientConnectionManager.setMaxTotal(maxTotalConnections);
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
        return poolingHttpClientConnectionManager;
    }

    @Bean(destroyMethod = "close")
    @Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT)
    public CloseableHttpClient closeableHttpClient(
            @Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT) PoolingHttpClientConnectionManager poolingHttpClientConnectionManager
    ) {
        log.info("CloseableHttpClient Build for {}", ConfigConstants.CONFIG_NAME_DEFAULT);
        return HttpClientBuilder.create().setConnectionManager(poolingHttpClientConnectionManager).build();
    }

    @Bean
    @Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT)
    public HttpComponentsClientHttpRequestFactory requestFactory(
            @Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT) CloseableHttpClient httpClient
    ) {
        log.info("HttpComponentsClientHttpRequestFactory Build for {}", ConfigConstants.CONFIG_NAME_DEFAULT);
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
        requestFactory.setReadTimeout(readTimeoutInMillis);
        requestFactory.setConnectTimeout(connectionTimeoutInMillis);
        requestFactory.setConnectionRequestTimeout(connectionRequestTimeoutInMillis);

        return requestFactory;
    }

    @Bean
    @Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT)
    public RestTemplate restTemplate(@Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT) RestTemplateBuilder builder,
            ResponseErrorHandler errorHandler
    )
    {
        log.info("RestTemplate Build for {}", ConfigConstants.CONFIG_NAME_DEFAULT);
        RestTemplate restTemplate = builder.build();
        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
        restTemplate.setErrorHandler(errorHandler);
        return restTemplate;
    }


    @Bean
    @Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT)
    public RestTemplateBuilder restTemplateBuilder(
            @Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT) HttpComponentsClientHttpRequestFactory requestFactory
    ) {
        log.info("RestTemplateBuilder Build for {}", ConfigConstants.CONFIG_NAME_DEFAULT);
        return new RestTemplateBuilder()
                .setReadTimeout(Duration.ofMillis(readTimeoutInMillis))
                .setConnectTimeout(Duration.ofMillis(connectionTimeoutInMillis))
                .requestFactory(
                        () -> requestFactory);

    }
}

And RestClient autowired into

public RestClient(@Qualifier(ConfigConstants.CONFIG_NAME_DEFAULT) RestTemplate restTemplate) {
    this.restTemplate = restTemplate;
}

Following code has been used to make call to

ResponseEntity<String> response = restTemplate.exchange(endpointURL, HttpMethod.POST, httpEntity, String.class);

Often service is working as expected.

But, it throws following error sometimes...

java.net.SocketException: Connection reset
        at java.base/java.net.SocketInputStream.read(SocketInputStream.java:186)
        at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
        at java.base/sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:478)
        at java.base/sun.security.ssl.SSLSocketInputRecord.readHeader(SSLSocketInputRecord.java:472)
        at java.base/sun.security.ssl.SSLSocketInputRecord.bytesInCompletePacket(SSLSocketInputRecord.java:70)
        at java.base/sun.security.ssl.SSLSocketImpl.readApplicationRecord(SSLSocketImpl.java:1364)
        at java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:973)
        at org.apache.http.impl.io.SessionInputBufferImpl.streamRead(SessionInputBufferImpl.java:137)
        at org.apache.http.impl.io.SessionInputBufferImpl.fillBuffer(SessionInputBufferImpl.java:153)
        at org.apache.http.impl.io.SessionInputBufferImpl.readLine(SessionInputBufferImpl.java:280)

After few minutes, the service is working as expected.

Could you please help me to fix this problem?

João Dias
  • 16,277
  • 6
  • 33
  • 45
sanssan
  • 305
  • 1
  • 3
  • 12

0 Answers0