SpringWebFlux

[Spring WebFlux] Controller vs Handler/Router 방식 비교

AGFE_ 2025. 3. 11. 15:51

Spring WebFlux: Controller vs Handler/Router 방식 비교

Spring WebFlux는 기존 Spring MVC와는 다른 리액티브 프로그래밍 기반의 웹 프레임워크임. WebFlux에서는 두 가지 방식으로 REST API를 구현할 수 있음.

  1. Controller 방식 (Annotated 방식, 기존 MVC 스타일)
  2. Handler/Router 방식 (Functional 스타일)

이 글에서는 두 가지 방식을 비교하고, 어떤 상황에서 어떤 방식을 선택해야 할지 설명함.


1. Controller 방식 (Annotated 기반, 기존 MVC 스타일)

Spring MVC 방식과 유사하게 @RestController, @RequestMapping 등의 어노테이션을 사용하여 API를 개발하는 방식임.

코드 예제 (Controller 방식)

@RestController
@RequestMapping("/users")
public class UserController {

    private final UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public Mono<ResponseEntity<User>> getUserById(@PathVariable String id) {
        return userService.getUserById(id)
            .map(user -> ResponseEntity.ok(user))
            .defaultIfEmpty(ResponseEntity.notFound().build());
    }

    @PostMapping
    public Mono<ResponseEntity<User>> createUser(@RequestBody User user) {
        return userService.createUser(user)
            .map(savedUser -> ResponseEntity.ok(savedUser));
    }
}

특징

✔ 기존 Spring MVC 스타일과 유사하여 익숙함
@RestController, @RequestMapping 등의 어노테이션을 그대로 활용 가능함
✔ WebFlux 기반이지만 동작 방식은 기존 MVC와 거의 동일함


2. Handler/Router 방식 (Functional 스타일)

Spring WebFlux에서 제공하는 Java 8+ Functional 스타일로 API를 구현하는 방식임.

  • RouterFunction을 사용해 API 라우팅을 정의함
  • HandlerFunction을 사용해 요청을 처리함
  • 완전한 함수형 프로그래밍 스타일을 지향함

코드 예제 (Handler/Router 방식)

1) Handler (요청 처리)

@Component
public class UserHandler {

    private final UserService userService;

    @Autowired
    public UserHandler(UserService userService) {
        this.userService = userService;
    }

    public Mono<ServerResponse> getUserById(ServerRequest request) {
        String id = request.pathVariable("id");
        return userService.getUserById(id)
            .flatMap(user -> ServerResponse.ok()
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(user))
            .switchIfEmpty(ServerResponse.notFound().build());
    }

    public Mono<ServerResponse> createUser(ServerRequest request) {
        return request.bodyToMono(User.class)
            .flatMap(userService::createUser)
            .flatMap(savedUser -> ServerResponse.ok()
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(savedUser));
    }
}

2) Router (라우팅 설정)

@Configuration
public class UserRouter {

    @Bean
    public RouterFunction<ServerResponse> route(UserHandler userHandler) {
        return RouterFunctions
            .route(RequestPredicates.GET("/users/{id}"), userHandler::getUserById)
            .andRoute(RequestPredicates.POST("/users"), userHandler::createUser);
    }
}

특징

✔ 기존 Spring MVC 방식보다 더 가벼운 API 서버 구현 가능함
람다식 활용 가능 → 코드가 간결해짐
✔ 완전히 함수형 스타일이라 DI 구조도 더 명확함
✔ 높은 확장성과 성능을 제공함