[Spring] RestTemplate, RestClient에 HttpClient 5 적용 하는법

klmin·2024년 10월 20일
0

Spring Boot : 3.3.4

HttpClient

HTTP 요청을 보내고, HTTP 응답을 받는 작업을 처리하는데 사용된다.

GET, POST, PUT, DELETE와 같은 다양한 HTTP 메서드를 지원하며 HTTP/1.1과 같은 표준 프로토콜을 사용하여 동기/비동기 방식으로 요청을 보낼 수 있다.

HTTP 요청 시 커넥션 풀, 타임아웃, 재시도 전략 등을 세부적으로 설정할 수 있어 네트워크와 통신 효율성을 최적화할 수 있다.

HttpCore

HTTP 프로토콜의 핵심 요소를 제공하는 라이브러리로 HttpClient가 정상적으로 동작하기 위해 필요하다.

HttpCore는 HTTP 메시지 처리와 관련된 저수준 API를 제공한다.

HTTP 요청 및 응답의 메시지 구조를 정의하고 커넥션과 스트림 처리 등의 핵심 기능을 처리한다.

일반적으로 HttpClient와 함께 사용되며 HTTP 메시지를 만들고 처리하는 기본 기능을 수행한다.

HttpClient5가 동작하기 위해서는 HttpCore5가 필수적으로 필요하다.

HttpCore-h2

HTTP/2 프로토콜을 지원하는 HttpCore의 확장 모듈이다.

HTTP/2는 기존 HTTP/1.1보다 더 나은 성능과 효율성을 제공하는 최신 HTTP 프로토콜이다.

다중화(multiplexing), 헤더 압축, 서버 푸시 등 새로운 기능을 지원한다.

HttpCore-h2는 Apache HttpClient가 HTTP/2 프로토콜을 사용하여 통신할 수 있도록 지원한다.

문제상황

기존 Spring4에서 사용하던 RestTemplate을 Spring6에서 설정하는 도중 HttpClient와 HttpComponentsClientHttpRequestFactory를 설정해서 사용하는 부분이 있었는데 Spring Boot 3.x에서 설정이 안되는 문제가 있어 HttpClient를 설정하는 법을 기록한다.

스프링 6에서는 기존에 사용되던 Apache HttpClient 지원이 제거되고 새로운 디펜던시인 org.apache.httpcomponents.client5:httpclient5로 대체되었다고 한다.

https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0-Migration-Guide#apache-httpclient-in-resttemplate

기존코드

HttpClient httpClient = HttpClientBuilder.create()
.setMaxConnTotal(200)
.setMaxConnPerRoute(100)
.setConnectionTimeToLive(5, TimeUnit.SECONDS).build();

HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(TIME_OUT);
factory.setConnectTimeout(TIME_OUT);
factory.setHttpClient(httpClient);

RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(factory);

return restTemplate;

HttpClient 설정 및 적용하는법

// build.gradle

implementation group: 'org.apache.httpcomponents.client5', name: 'httpclient5', version: '5.4'
implementation group: 'org.apache.httpcomponents.core5', name: 'httpcore5', version: '5.3'
implementation group: 'org.apache.httpcomponents.core5', name: 'httpcore5-h2', version: '5.3'

gradle에서 추가한 jar가 생긴다.

//HttpClient 설정

 @Bean
 public HttpClient httpClient(){

        int maxPool = 200; // 전체 커넥션 풀에서 사용할 수 있는 최대 커넥션 수
        int maxPerRoute = 100; // 각 호스트(서버)당 커넥션 풀에서 사용할 수 있는 최대 커넥션 수
        long validateAfterInactivity = 5L; // 유휴상태 검증 시간
        int idleConnectionTimeoutSec = 30; // 유휴 커넥션이 이 시간이 지나면 풀에서 제거되는 시간
        long requestTimeOut = 5000L; // 커넥션 풀에서 커넥션을 얻기 위해 대기할 수 있는 최대 시간
        long readTimeOut = 5000L; // 서버로부터 응답을 기다리는 최대 시간
        int retryCount = 1; // 예외가 발생했을 때 요청을 재시도할 최대 횟수
        long backoff = 1000; // 재시도 간의 대기 시간

        // 커넥션 관리 매니저 (커넥션 풀을 관리하는 매니저)
        PoolingHttpClientConnectionManager connManager = new PoolingHttpClientConnectionManager();
        connManager.setMaxTotal(maxPool);
        connManager.setDefaultMaxPerRoute(maxPerRoute);
        connManager.setDefaultSocketConfig(SocketConfig.DEFAULT); // 기본 TCP 소켓 설정
        connManager.setDefaultConnectionConfig(ConnectionConfig
                .custom()
                .setValidateAfterInactivity(Timeout.ofSeconds(validateAfterInactivity))
                .build()); // 유휴 상태에서 커넥션을 재사용하기 전에 유효성 검사를 수행 (서버와의 연결이 끊겼는지 확인)


        // 요청 관련 다양한 설정을 제공 (타임아웃 관련 설정)
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectionRequestTimeout(Timeout.ofMilliseconds(requestTimeOut))
                .setResponseTimeout(Timeout.ofMilliseconds(readTimeOut))
                .build();

        return HttpClients.custom()
                .setConnectionManager(connManager)
                .setDefaultRequestConfig(requestConfig)
                .setConnectionBackoffStrategy(new DefaultBackoffStrategy()) // 네트워크 오류 발생 시 재시도 간 백오프전략
                .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) // 서버가 보낸 Keep-Alive 헤더 값에 따라 커넥션을 유지하는 전략
                .setRetryStrategy(new DefaultHttpRequestRetryStrategy(retryCount, TimeValue.ofMilliseconds(backoff))) // 네트워크 오류 또는 일시적인 서버 문제 발생 시 재시도 전략
                .evictIdleConnections(TimeValue.ofSeconds(idleConnectionTimeoutSec)) // 유휴 커넥션이 사용되지 않았을 경우 커넥션을 종료하고 풀에서 제거
                .build();
    }
    

RestTemplate

@Bean
public RestTemplate restTemplate(HttpClient httpClient){
	return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
}

RestClient

@Bean
public RestClient restClient(HttpClient httpClient) {
       return RestClient.builder()
                .requestFactory(new HttpComponentsClientHttpRequestFactory(httpClient))
                .build();
}

참고 : https://joyfulviper.tistory.com/106

https://hc.apache.org/httpcomponents-client-5.4.x/migration-guide/migration-to-classic.html

profile
웹 개발자

0개의 댓글