Spring WebFlux: Controller vs Handler/Router 방식 비교
Spring WebFlux는 기존 Spring MVC와는 다른 리액티브 프로그래밍 기반의 웹 프레임워크임. WebFlux에서는 두 가지 방식으로 REST API를 구현할 수 있음.
- Controller 방식 (Annotated 방식, 기존 MVC 스타일)
- 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 구조도 더 명확함
✔ 높은 확장성과 성능을 제공함