Contents
see List작성일 2025. 11. 30.
Spring WebFlux란?
Spring WebFlux는 Spring 5에서 도입된 리액티브 웹 프레임워크입니다. 논블로킹(Non-blocking) I/O를 기반으로 적은 스레드로 많은 동시 요청을 처리할 수 있어, 높은 동시성이 필요한 시스템에 적합합니다.
언제 사용하나요?
- 대용량 스트리밍 데이터 처리 (실시간 피드, 채팅)
- 마이크로서비스 간 비동기 통신
- I/O 바운드 작업이 많은 API 서버
- MSA 환경에서 다수의 외부 API 호출
MVC vs WebFlux 비교
| 항목 | Spring MVC | Spring WebFlux |
|---|---|---|
| I/O 모델 | 블로킹 | 논블로킹 |
| 스레드 | 요청당 1스레드 | 이벤트 루프 |
| 반환타입 | Object | Mono/Flux |
| 서버 | Tomcat | Netty |
기본 의존성
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>Mono와 Flux 이해하기
// Mono: 0 또는 1개의 결과
Mono<User> user = userRepository.findById(id);
// Flux: 0 ~ N개의 결과 (스트림)
Flux<User> users = userRepository.findAll();
// 생성 방법
Mono<String> mono = Mono.just("Hello");
Flux<Integer> flux = Flux.just(1, 2, 3, 4, 5);
Flux<Integer> range = Flux.range(1, 10);리액티브 컨트롤러
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
@GetMapping("/{id}")
public Mono<User> getUser(@PathVariable Long id) {
return userService.findById(id);
}
@GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<User> streamUsers() {
return userService.findAll()
.delayElements(Duration.ofMillis(500));
}
@PostMapping
public Mono<User> createUser(@RequestBody Mono<User> user) {
return user.flatMap(userService::save);
}
}WebClient - 리액티브 HTTP 클라이언트
@Service
public class ExternalApiService {
private final WebClient webClient;
public ExternalApiService(WebClient.Builder builder) {
this.webClient = builder
.baseUrl("https://api.example.com")
.defaultHeader(HttpHeaders.CONTENT_TYPE,
MediaType.APPLICATION_JSON_VALUE)
.build();
}
public Mono<ApiResponse> callApi(String path) {
return webClient.get()
.uri(path)
.retrieve()
.onStatus(HttpStatus::is4xxClientError,
response -> Mono.error(new ClientException()))
.bodyToMono(ApiResponse.class)
.timeout(Duration.ofSeconds(5))
.retry(3);
}
// 여러 API 동시 호출
public Mono<CombinedResult> callMultipleApis() {
Mono<A> apiA = callApiA();
Mono<B> apiB = callApiB();
return Mono.zip(apiA, apiB, CombinedResult::new);
}
}에러 처리
Mono<User> user = userRepository.findById(id)
.switchIfEmpty(Mono.error(new NotFoundException()))
.onErrorResume(e -> {
log.error("Error: ", e);
return Mono.empty();
})
.onErrorReturn(new User()); // 기본값 반환R2DBC - 리액티브 DB 접근
// 의존성
// spring-boot-starter-data-r2dbc
// r2dbc-postgresql
@Repository
public interface UserRepository
extends ReactiveCrudRepository<User, Long> {
Flux<User> findByStatus(String status);
@Query("SELECT * FROM users WHERE age > :age")
Flux<User> findOlderThan(int age);
}주의사항
- 블로킹 코드(JDBC, RestTemplate)와 혼용 금지
- CPU 바운드 작업에는 부적합
- 디버깅이 상대적으로 어려움
- 기존 MVC 애플리케이션과 완전 호환되지 않음
spring
| No | 작성일 | Title |
|---|---|---|
| 2005 | 2025. 11. 30. | Spring Security 6 JWT 인증 구현 |
| 2004 | 2025. 11. 30. | Spring Boot 3.x 새로운 기능 정리 |
| 1824 | 2022. 05. 24. | [ spring ] interceptor 등 스프링에서 @Autowired 인식을 못할때 |
| 421 | 2016. 08. 02. | [ spring-security ] 스프링 시큐리티 csrf (크로스도메인) 설정방법 |
| 349 | 2016. 02. 16. | [ spring ] spring4 jsonp callback |
| 346 | 2016. 02. 08. | [ spring 4 ] 스프링 4 websocket 및 stomp (채팅 및 쪽지 구현) |
| 344 | 2016. 02. 06. | [ spring-security ] 스프링 시큐리티 4 버전에서 hasRole 및 hasAnyRole 안될경우 |
| 328 | 2015. 11. 05. | [ spring security ] 스프링 시큐리티 유저정보 얻는 방법 |
| 311 | 2015. 06. 30. | [ spring ] IOException while loading persisted sessions: java.io.EOFException 해결 |
| 310 | 2015. 06. 29. | [ spring ] How To Get HTTP Request Header In spring ( 스프링에서 http header 값 가져오기) |