spring

RestTemplate 사용법

ppthejake 2023. 10. 30. 15:42

Connection Pool 사용

RestTemplate 은 내부적으로 Apache HttpComponents 라이브러리를 사용합니다. http 요청 시, RestTemplate 은 매번 새로운 연결을 맺고 이로 인하여 대량의 요청을 처리할 때 상당한 오버헤드가 발생할 수 있다.

이를 회피하기 위해 RestTemplate 이 매번 새로운 연결을 맺는 대신에 재사용 할 수 있는 커넥션 풀을 구성하여 사용하는 것이 좋다. Spring 에서는 RestTemplate 을 위한 커넥션 풀을 구성할 수 있도록 HttpClientConnectionManager 인터페이스를 제공한다.

 

@Bean
public RestTemplate restTemplate() {

    HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
    httpRequestFactory.setConnectionRequestTimeout(5000);
    httpRequestFactory.setConnectTimeout(5000);

    PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
    connectionManager.setMaxTotal(50);
    connectionManager.setDefaultMaxPerRoute(20);
    connectionManager.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(5000, TimeUnit.MILLISECONDS).build());
    
    CloseableHttpClient httpClient = HttpClientBuilder.create()
            .setConnectionManager(connectionManager)
            .build();

    httpRequestFactory.setHttpClient(httpClient);

    return new RestTemplate(httpRequestFactory);
}

위의 코드를 살펴보면

1) 최대 50개의 연결과 라우트 당 최대 20개의 연결을 가질 수 있는 커넥션 풀 생성하여

2) HttpComponentsClientHttpRequestyFactory 에 추가해 줍니다.

3) 또한, http 요청시 무기한 대기하는것을 방지하기 위하여 적절한 시간 초과 값을 설정합니다.
    (연결 시간 및 소켓 리드타임을 5초로 설정)

ResponseErrorHandler  재정의

RestTemplate은 ResponseErrorHandler 인터페이스를 통해 http 오류를 처리하는 방법을 제공한다. 이를 통해 http 상태코드와 오류응답을 처리하는 사용자 정의할 수 있다. 기본적으로 RestTemplate 은 4xx 와 5xx 의 http 상태코드에 대해 예외를 던지게 되어있다.

RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
		// 에러 응답 처리
    }
});

응답에 ParameterizedTypeReference 사용

리스트나 맵과 같은 타입의 응답을 받는 경우 타입추론을 할 수 없습니다. 이러한 경우 유형을 지정하지 위해 ParameterizedTypeReference 클래스를 사용하여 응답 유형을 정의할 수 있습니다.

RestTemplate restTemplate = new RestTemplate();
ParameterizedTypeReference<List<MyObject>> responseType = new ParameterizedTypeReference<>() {};
ResponseEntity<List<MyObject>> response = restTemplate.exchange(url, HttpMethod.POST, null, responseType);
List<MyObject> myObjects = response.getBody();

위 코드에서는 ParameterizedTypeReference 를 사용하여 응답유형을 정의하고 응답을 List<MyObject> 로 반환합니다.

RestTemplateBuilder 사용을 통한 설정 간소화

RestTemplate 을 간단하게 구성하기 위한 builder 를 제공합니다. 연결초과시간, 읽기초과시간, 인터셉터 등 설정을 쉽게 정의할 수 있습니다.

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    return builder
            .setConnectTimeout(Duration.ofSeconds(5))
            .setReadTimeout(Duration.ofSeconds(5))
            .build();
}

요청/응답 Interceptor  정의

http 요청 및 응답에 대한 인터셉터를 정의할 수 있습니다. 이를 통해 헤더 추가나 로깅과 같은 작업을 수행할 수 있습니다.

RestTemplateBuilder 나 RestTemplate 의 interceptors() 메소드를 사용하여 인터셉터를 추가할 수 있습니다.

  • 요청헤더에 인증토큰 삽입
public class AuthInterceptor implements ClientHttpRequestInterceptor {
    private String authToken;
    
    public AuthInterceptor(String authToken) {
        this.authToken = authToken;
    }
    
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        request.getHeaders().add("Authorization", "Bearer " + authToken);
        return execution.execute(request, body);
    }
}
  • 요청 / 응답 관련 로깅
@Slf4j
public class LoggingInterceptor implements ClientHttpRequestInterceptor {
    
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        // 요청 로그 기록
        logRequest(request, body);
        ClientHttpResponse response = execution.execute(request, body);
        // 응답 로그 기록
        logResponse(response);
        return response;
    }
    
    private void logRequest(HttpRequest request, byte[] body) {
        log.info("Request Log: ...");
    }
    
    private void logResponse(ClientHttpResponse response) throws IOException {
        log.info("Response Log: ...");
    }
}

직렬화를 위한 HttpMessageConverters 사용

RestTemplate 은 HttpMessageConverters 를 사용하여 Http 요청 및 응답에 대한 데이터 직렬화, 역직렬화 합니다.  Spring 에서는 JSON 직렬화를 위하여 MappingJackson2HttpMessageConverter 와 같은 여러 내장 HttpMessageConverters 를 제공합니다.

RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(List.of(new MappingJackson2HttpMessageConverter()));