1. 개요
@RestControllerAdvice를 사용하여 전역 예외 처리를 하는 코드에서 원하는 응답값이 나오지 않고 다음과 같은 응답값이 지속적으로 나와서 해당 부분의 원인을 찾다가 spring.main.web-application-type를 reactive로 설정해야한다는 내용을 발견하여서 관련 내용을 정리해본다.
package me.progfrog.idol.flow.exception;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import reactor.core.publisher.Mono;
@RestControllerAdvice
public class ApplicationAdvice {
@ExceptionHandler({
ApplicationException.class
})
public Mono<ResponseEntity<ServerExceptionResponse>> applicationExceptionHandler(ApplicationException ex) {
return Mono.just(ResponseEntity
.status(ex.getHttpStatus())
.body(new ServerExceptionResponse(ex.getCode(), ex.getReason())));
}
public record ServerExceptionResponse(
String code,
String reason
) {
}
}
원하는 형태는 이건데..
{
"code": "UQ-0001",
"reason": "이미 대기열에 등록된 사용자 입니다."
}
계속 이 응답으로 내려왔다!
{
"scanAvailable": true
}
두둥...
리액티브 응답은 기본적으로 JSON 형식을 사용하며, Mono 또는 Flux로 래핑된 데이터가 반환된다. 위와 같이 리액티브 웹 애플리케이션 코드를 작성하였더라도, 웹 애플리케이션 타입이 servlet으로 설정되어 있다면 스프링 부트는 서블릿 컨텍스트에서 애플리케이션을 실행하려고 시도한다. 이 경우 전통적인 서블릿 기반 요청 처리를 사용하여 리액티브 코드를 실행한다. 따라서, 의도한 리액티브 처리가 되지 않고 위와 같은 응답이 나오는 것으로 보인다.
2. spring.main.web-application-type 종류
이 코드는 스프링 부트 애플리케이션의 application.properties 또는 application.yml 파일에 설정된 속성이다. 이 속성은 스프링 부트 애플리케이션이 사용할 웹 애플리케이션 타입을 지정한다. 주로 SpringApplication의 실행 환경을 설정하는 데 사용되며, 다양한 웹 애플리케이션 타입 중 하나를 선택할 수 있다. 이 속성의 가능한 값은 none, servlet, reactive이다.
none
- 웹 환경을 비활성 한다.
- 애플리케이션이 웹 서버를 시작하지 않는다.
- 주로 CLI 애플리케이션이나 배치작업에 사용된다.
- spring-boot-starter-web 또는 spring-boot-starter-webflux 의존성이 포함되어 있지 않은 경우
servlet
- 서블릿 기반 웹 애플리케이션으로 설정한다.
- 전통적인 Spring MVC 애플리케이션에서 사용된다.
- spring-boot-starter-web 의존성이 포함된 경우
reactive
- 리액티브 웹 애플리케이션으로 설정한다.
- 리액티브 스트림을 기반으로 비동기 및 논블로킹 방식의 웹 애플리케이션을 작성할 때 사용된다.
- spring-boot-starter-webflux 의존성이 포함된 경우
3. reactive로 설정하기
작업하고 있던 프로젝트의 경우 spring-boot-starter-web과 spring-boot-starter-webflux를 모두 사용하고 있었는데, 이 경우는 servlet 타입을 기본적으로 우선한다고 한다. 그래서 리액티브 웹 애플리케이션을 우선하도록 하기위해 application.properties 파일에 명시적으로 작성해주었다.
spring.main.web-application-type=reactive
이렇게 설정한 경우, 애플리케이션은 리액티브 프로그래밍 모델을 사용하여 웹 애플리케이션을 구축하게 된다. 이는 다음과 같은 특징을 가진다.
논블로킹 I/O
네트워크와 데이터베이스와 같은 I/O 작업이 블로킹되지 않고, 요청이 들어올 때마다 새로운 스레드를 생성하지 않는다.
리액티브 스트림 지원
Reactor와 같은 리액티브 스트림 라이브러리를 사용하여 데이터 흐름을 관리한다.
고성능, 고확장성
많은 동시 요청을 효율적으로 처리할 수 있어, 고성능과 고확장성을 요구하는 애플리케이션에 적합하다.
WebFlux
Spring WebFlux 모듈을 사용하여, 리액티브 방식의 REST API나 웹 애플리케이션을 개발할 수 있다.
사용 예
- 대규모의 동시 접속자가 있는 시스템
- 실시간 데이터 스트리밍 애플리케이션
- 비동기 처리 및 비동기 API 호출이 많이 필요한 경우