RestTemplate이란

RestTemplate을 싱글턴으로 사용해야 하는 이유

Connection Pool

RestTemplate + Connection Pool 적용 예시

@Bean
public PoolingHttpClientConnectionManager poolingConnectionManager() {
	// Apache에서 제공하는 커넥션 풀 매니저로 TCP 연결을 재사용하기 위해 반드시 필요
	PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
	// 전체 커넥션 수
	connectionManager.setMaxTotal(100);
	// 도메인당 커넥션 수
	connectionManager.setDefaultMaxPerRoute(20);
	return connectionManager;
}

@Bean
public CloseableHttpClient httpClient(PoolingHttpConnectionManager connectionManager) {
	// Apache 실제 Http 클라이언트 구현체로 HTTP 요청 전송의 주체
	// custom() = HttpClientBuilder 생성하는 정적 팩토리 메서드
	return HttpClients.custom()
		// 위에서 생성한 커넥션 풀 설정
		.setConnectionManager(connectionManager)
		// 유휴 커넥션 제거
		.evictIdleConnection(30, TimeUnit.SECONDS)
		.build();
}

@Bean
public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory(CloseableHttpClient httpClient) {
	// RestTemplate이 사용할 HTTP 요청 생성기(팩토리 역할)
	HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
	// 기본값은 대기를 무한으로 하기 때문에 타임아웃 설정
	// TCP 연걸을 맺을 때까지 기다리는 최대 시간
	factory.setConnectionTimeout(5000);
	// 응답 바디를 읽을 때까지 기다리는 최대 시간
	factory.setReadTimeout(5000);
	return factory;
}

@Bean
public RestTemplate restTemplate() {
	return new RestTemplate(factory);
}

RestTemplate + Connection Pool 적용 예시(xml 기반)

<!-- 1. 커넥션 풀 매니저 -->
<!-- 이 컴포넌트가 실제 HTTP 연결을 풀로 관리 -->
<bean id="httpClientConnectionManager" class="org.apache.http.impl.conn.PoolingHttpClientConnectionManager">
    <property name="maxTotal" value="100"/>
    <property name="defaultMaxPerRoute" value="20"/>
</bean>

<!-- 2. HttpClientBuilder 생성 -->
<!-- HttpClients.custom() 정적 메서드 호출 -->
<!-- Apache HttpClient는 빌더 패턴 기반이라 HttpClientBuilder 통해 설정을 체이닝 -->
<bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
    <!-- factory-method="create"로 정적 메서드 호출 -->
</bean>

<!-- 3. connectionManager 주입 -->
<!-- httpClientBuilder.setConnectionManager()에 해당하며 빌더에 커넥션 풀을 주입 -->
<bean id="httpClientWithPoolBuilder" factory-bean="httpClientBuilder" factory-method="setConnectionManager">
    <constructor-arg ref="httpClientConnectionManager"/>
</bean>

<!-- 4. 실제 HttpClient 생성 -->
<!-- 커넥션 풀 설정을 포함한 CloseableHttpClient 생성, 이 객체가 실제 HTTP 요청 처리 -->
<bean id="httpClient" factory-bean="httpClientWithPoolBuilder" factory-method="build" class="org.apache.http.impl.client.CloseableHttpClient"/>

<!-- 5. HttpRequestFactory 설정 -->
<!-- RestTemplate이 HTTP 요청을 만들기 위해 이 팩토리 객체를 사용하며, 이곳에서 Apache HttpClient 통해 커넥션 풀 기반 통신을 하게 됨 -->
<bean id="httpRequestFactory" class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
    <constructor-arg ref="httpClient"/>
    <property name="connectTimeout" value="5000"/>
    <property name="readTimeout" value="5000"/>
</bean>

<!-- 6. RestTemplate 등록 -->
<!-- 내부적으로 HttpComponentsClienthttpRequestFactory가 실행되며 커넥션은 PoolingHttpClientConnectionManager로부터 재사용 -->
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
    <constructor-arg ref="httpRequestFactory"/>
</bean>

관계도 및 흐름 정리

image.png