Web Development/Spring

[Spring] WebClient - 1. 개념 및 기본 설정

graycode 2025. 2. 26. 17:55

WebClient 란

WebClient 는 Spring 5 에서 도입된 비동기적이고 논블로킹 방식의 HTTP 클라이언트이다.

Spring WebFlux 스택의 일부로, Reactive 프로그래밍 모델을 지원한다.

📌​ 장점

 1. Non-Blocking 처리

  • 논 블로킹 방식으로 동작하여 시스템 리소스를 효율적으로 사용
  • 다수의 API 호출을 동시에 처리

 2. Reactive Streams 지원

  • Flux 와 Mono 를 통한 반응형 스트림 처리 가능
  • 백프레셔(backpressure) 기능을 제공하여 데이터 처리 과부하 제어

 3. 유연한 API

  • 메소드 체이닝을 통한 직관적인 API 구성 가능
  • 다양한 요청 / 응답 변환기 제공

⚠️​ 단점

 1. 학습 곡선

  • Reactive 프로그래밍 패러다임에 대한 이해 필요
  • 기존의 동기식 프로그래밍과는 다른 접근 방식 요구

 2. 디버깅의 어려움

  • 비동기 스택 트레이스가 복잡함
  • 에러 추적이 상대적으로 어려울 수 있음

 3. 리소스 사용

  • 초기 구동 시 더 많은 메모리를 사용
  • 단순한 요청의 경우 RestTemplate 보다 오버헤드가 있을 수 있음

✅​ 사용 권장 상황

  • 대규모 동시 요청 처리가 필요한 경우
  • 스트리밍 데이터 처리가 필요한 경우
  • 비동기 처리가 필요한 고성능 애플리케이션인 경우

WebClient 기본 설정

WebClient 를 사용하기 위해 필요한 디펜던시를 설정한다. (Maven 기준 SpringBoot 디펜던시 별도)

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-netty</artifactId>
</dependency>

📃​ WebClientConfig

WebClient 를 구성하고 설정할 클래스를 정의한다.

public class WebClientConfig {

    /**
     * WebClient 객체 생성
     *
     * @param httpClient HttpClient
     * @param exchangeStrategies ExchangeStrategies
     * @return HttpClient
     */
    public WebClient buildWebClient(HttpClient httpClient, ExchangeStrategies exchangeStrategies) {
        return WebClient.builder()
                .clientConnector(new ReactorClientHttpConnector(httpClient))
                .exchangeStrategies(exchangeStrategies)
                .build();
    }

    /**
     * HttpClient 타임아웃 설정 및 반환
     *
     * @param timeout int
     * @return HttpClient
     */
    public HttpClient getHttpClient(int timeout) {
        return HttpClient.create()
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout)
                .responseTimeout(Duration.ofMillis(timeout))
                .doOnConnected(conn -> conn
                        .addHandlerLast(new ReadTimeoutHandler(timeout, TimeUnit.MILLISECONDS))
                        .addHandlerLast(new WriteTimeoutHandler(timeout, TimeUnit.MILLISECONDS)));
    }

    /**
     * 인 메모리 버퍼 설정
     *
     * @param byteCount int
     * @return ExchangeStrategies
     */
    public ExchangeStrategies getExchangeStrategies(int byteCount) {
        return ExchangeStrategies.builder()
                .codecs(config -> config.defaultCodecs().maxInMemorySize(byteCount))
                .build();
    }

    /**
     * 논 블로킹 IO 구성 시 사용
     *
     * @return ConnectionProvider
     */
    public ConnectionProvider getConnectionProvider() {
        return ConnectionProvider.builder("http-pool")
                .maxConnections(100)
                .pendingAcquireTimeout(Duration.ofMillis(0))
                .pendingAcquireMaxCount(-1)
                .maxIdleTime(Duration.ofMillis(2000L))
                .build();
    }

}

 

아래는 해당 클래스의 각 메소드에 대한 내용을 주석과 함께 설명한다.

​📑 getHttpClient

HttpClient 객체를 생성하고 전달된 타임아웃 값을 설정해 반환한다.

public HttpClient getHttpClient(int timeout) {
    return HttpClient.create() // HttpClient 생성, 논 블로킹 IO 구성 시 ConnectionProvider 를 create 메소드의 파라미터로 전달
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout) // 서버와의 연결 시도 제한시간 
            .responseTimeout(Duration.ofMillis(timeout)) // 응답 대기 제한 시간
            .doOnConnected(conn -> conn
                    .addHandlerLast(new ReadTimeoutHandler(timeout, TimeUnit.MILLISECONDS)) // 데이터 읽기 작업 제한 시간
                    .addHandlerLast(new WriteTimeoutHandler(timeout, TimeUnit.MILLISECONDS))); // 데이터 쓰기 작업 제한 시간
}

​📑 getConnectionProvider

논 블로킹 IO 구성 시 사용하며, 생성한 ConnectionProvider 객체를

getHttpClient 함수에 HttpClient.create(ConnectionProvider) 와 같이 전달한다.

public ConnectionProvider getConnectionProvider() {
    return ConnectionProvider.builder("http-pool") // 커넥션 풀 구성
            .maxConnections(100) // 최대 동시 연결 수
            .pendingAcquireTimeout(Duration.ofMillis(0)) // 연결 획득 대기 시간
            .pendingAcquireMaxCount(-1) // 대기 중인 최대 획득 요청 수 (-1 일 시 무제한)
            .maxIdleTime(Duration.ofMillis(2000L)) // 유휴 연결의 최대 유지 시간
            .build();
}

​📑 getExchangeStrategies

데이터 교환 정책 설정을 위해, ExchangeStrategies 객체를 생성하고 전달된 인메모리 버퍼 크기를 설정하여 반환한다.

public ExchangeStrategies getExchangeStrategies(int byteCount) {
    return ExchangeStrategies.builder() // ExchangeStrategies 구성
            .codecs(config -> config.defaultCodecs().maxInMemorySize(byteCount)) // 인메모리 버퍼 사이즈 설정
            .build();
}

​📑 buildWebClient

HttpClient 와 ExchangeStrategies 를 조합하여 WebClient 객체를 반환한다.

public WebClient buildWebClient(HttpClient httpClient, ExchangeStrategies exchangeStrategies) {
    return WebClient.builder() // WebClient 구성
            .clientConnector(new ReactorClientHttpConnector(httpClient)) // HttpClient 를 WebClient 와 연결
            .exchangeStrategies(exchangeStrategies) // 데이터 교환 전략 설정
            .build();
}

📃​ WebClientFactory

다음은 WebClient 객체를 서비스 단에서 사용하기 위한 팩토리 클래스를 정의한다.

@Getter
@Service
public class WebClientFactory {

    private final WebClient webClient;

    public WebClientFactory() {
        this.webClient = createWebClient();
    }

    /**
     * WebClient 객체 반환
     *
     * @return WebClient
     */
    public WebClient createWebClient() {
        WebClientConfig webClientConfig = new WebClientConfig();

        return webClientConfig.buildWebClient(
                webClientConfig.getHttpClient(5000), // HttpClient 구성
                webClientConfig.getExchangeStrategies(1024 * 1024)); // ExchangeStrategies 구성
    }

}

 

 

이러한 WebClient 설정 구성을 통해, 리소스의 사용을 효율적으로 관리하고, 안정성을 향상시킬 수 있다.

이후 요청에 대한 핸들링과 API 구성에 대한 내용은 다음 장에 기술한다.

 

🔗[Spring] WebClient - 2. 요청 핸들링 및 API 구성