Skip to content

Instantly share code, notes, and snippets.

@mingyu-kwak
Last active July 24, 2021 04:14
Show Gist options
  • Select an option

  • Save mingyu-kwak/afd93109c0c3798bec059277f003b69d to your computer and use it in GitHub Desktop.

Select an option

Save mingyu-kwak/afd93109c0c3798bec059277f003b69d to your computer and use it in GitHub Desktop.
Apache HttpComponents를 이용한 RestTemplate Bean 등록
package local.mike.simpleboard.configure;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
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.*;
import org.springframework.web.client.RestTemplate;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
/**
* <p><b>
* HTTP 상의 Rest API를 호출하기 위해 RestTemplate 객체를 설정하고 Bean 등록하는 클래스.
* </b></p>
*
* Database 연결 시 사용하는 Connection Pool과 같이 Http Client도 Connection Pool을 만들어
* 사용해야 많은 요청 시 소켓을 미리 확보 및 제한해 효율적으로 통신할 수 있도록
* 만들어 줄 수 있다.
*
* 아래는 Apache HttpComponents Library를 이용해 커넥션 풀을 만들어 RequestFactory에 등록하고
* Interceptor를 사용해 Log 정보를 출력하는 RestTemplate 객체를 만들어 Bean으로 등록해 둔다.
*/
@Configuration
@Slf4j
public class HttpClientConfiguration {
private final int readTimeoutSeconds;
private final int connectTimeoutSeconds;
private final int maxIdleConnections;
private final int keepAliveMinutes;
public HttpClientConfiguration(@Value("${http-client.read-timeout-seconds}") int readTimeoutSeconds,
@Value("${http-client.connect-timeout-seconds}") int connectTimeoutSeconds,
@Value("${http-client.max-idle-connections}") int maxIdleConnections,
@Value("${http-client.keep-alive-minutes}") int keepAliveMinutes) {
this.readTimeoutSeconds = readTimeoutSeconds;
this.connectTimeoutSeconds = connectTimeoutSeconds;
this.maxIdleConnections = maxIdleConnections;
this.keepAliveMinutes = keepAliveMinutes;
}
private HttpClientConnectionManager httpClientConnectionManager() {
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
manager.closeIdleConnections(keepAliveMinutes, TimeUnit.MINUTES);
manager.setMaxTotal(maxIdleConnections);
manager.setDefaultMaxPerRoute(5);
return manager;
}
private RequestConfig requestConfig() {
return RequestConfig.custom()
.setConnectionRequestTimeout(connectTimeoutSeconds)
.setConnectTimeout(connectTimeoutSeconds)
.setSocketTimeout(connectTimeoutSeconds)
.build();
}
@Bean
public HttpClient httpClient() {
return HttpClients.custom()
.setConnectionManager(httpClientConnectionManager())
.setDefaultRequestConfig(requestConfig())
.disableCookieManagement()
.build();
}
/**
* RestTemplateBuilder를 통해 HttpClient를 이용한 ClientHttpRequestFactory와
* 아래서 설정한 Log를 찍기 위한 Interceptor를 설정한다.
* @param httpClient HttpClient 객체
* @return 서비스에서 호출 가능한 RestTemplate 객체
*/
@Bean
public RestTemplate restTemplate(HttpClient httpClient) {
return new RestTemplateBuilder()
.setReadTimeout(Duration.ofSeconds(readTimeoutSeconds))
.requestFactory(() -> new BufferingClientHttpRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient)))
.interceptors(clientHttpRequestInterceptor())
.build();
}
/**
* HTTP Client 사용 시 Log를 찍기 위한 Interceptor 객체.
* ClientHttpRequestInterceptor 인터페이스를 람다로 통해 익명 객체화 하여 리턴한다.
* @return Log를 찍기 위한 로직이 들어있는 ClientHttpRequestInterceptor 익명 객체
*/
private ClientHttpRequestInterceptor clientHttpRequestInterceptor() {
return (httpRequest, bodyBytes, execution) -> {
if (log.isDebugEnabled()) {
log.debug("HttpClientRequest {} {}, body: {}", httpRequest.getMethodValue(), httpRequest.getURI(), bodyBytes);
}
ClientHttpResponse execute = execution.execute(httpRequest, bodyBytes);
if (log.isDebugEnabled()) {
log.debug("HttpClientResponse state: {}", execute.getRawStatusCode());
log.debug("HttpClientResponse body: {}", execute.getBody());
}
return execute;
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment