반응형

 

Mono와 Flux

Mono와 Flux는 스프링 WebFlux에서 리액티브 프로그래밍을 위해 제공되는 두 가지 기본 리액터 타입

이때 Mono는 하나의 아이템만 발행하며, Flux는 여러개의 아이템을 발행할 수 있다.

  • Mono: 0개 또는 1개의 아이템을 발행할 수 있는 리액티브 시퀀스
  • Flux: 0개 또는 N개의 아이템을 발행할 수 있는 리액티브 시퀀스

리액티브 프로그래밍에서는 비동기적으로 실행되는 작업들을 스트림(Stream)이라고 한다.

Mono와 Flux는 이러한 스트림을 다루기 위한 리액터 타입으로, 스트림이 발행하는 값을 처리하는데 유용하다.

 

 

Mono와 Flux Example

아래 예시를 통해 Mono와 Flux를 살펴보자.

// Mono 예제
Mono.just("Hello, World!")
    .subscribe(System.out::println);

// Flux 예제
Flux.just("apple", "banana", "orange")
    .subscribe(System.out::println);

 

위 코드에서 Mono.just() Flux.just() 메소드를 사용하여 각각 하나의 값을 발행하는 Mono와 여러개의 값을 발행하는 Flux를 볼 수 있다. 그리고 subscribe() 메소드를 사용하여 Mono와 Flux가 발행하는 값들을 구독한다.

이 때, System.out::println을 통해 구독자가 구독하는 Mono나 Flux에서 발행되는 값들을 출력하는 람다 표현식이다.

 

 

이번엔 좀 더 복합한 Mono와 Flux 예제를 살펴보자. 이 예제는 Spring WebFlux에서 MongoDB를 사용하여

사용자를 생성, 업데이트, 삭제하고, 사용자 목록을 검색하는 API를 제공하는 UserService 클래스를 볼 수 있다.

@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public Mono<User> getUserById(String id) {
        return userRepository.findById(id)
                .switchIfEmpty(Mono.error(new UserNotFoundException("User not found with id: " + id)));
    }

    public Flux<User> getAllUsers() {
        return userRepository.findAll();
    }

    public Mono<User> createUser(User user) {
        return userRepository.save(user);
    }

    public Mono<User> updateUser(String id, User user) {
        return userRepository.findById(id)
                .flatMap(existingUser -> {
                    existingUser.setName(user.getName());
                    existingUser.setEmail(user.getEmail());
                    return userRepository.save(existingUser);
                })
                .switchIfEmpty(Mono.error(new UserNotFoundException("User not found with id: " + id)));
    }

    public Mono<Void> deleteUserById(String id) {
        return userRepository.deleteById(id);
    }
}

 

  • getUserById()
    getUserById() 메소드는 id가 사용자인 사용자를 찾아서 Mono로 반환한다.
    만약 해당 ID를 가진 사용자가 없다면 switchIfEmpty() 메소드를 사용하여 UserNotFoundException 예외를 발생시킨다.
  • getAllUsers()
    getAllUsers() 메소드는 모든 사용자를 검색하여 Flux로 반환한다.
  • createUser()
    createUser() 메소드는 새로운 사용자를 생성하고, Mono로 반환한다.
  • updateUser()
    updateUser() 메소드는 ID가 id인 사용자를 찾아서 업데이트하고, Mono로 반환한다.
    만약 해당 ID를 가진 사용자가 없다면, switchIfEmpty() 메소드를 사용하여 UserNotFoundException 예외를 발생시킨다.
  • deleteUserById()
    deleteUserById() 메소드는 ID가 id인 사용자를 삭제하고, Mono<Void>로 반환한다.

 

 

위의 코드에서 UserService 클래스는 Mono와 Flux를 사용하여 비동기적으로 실행되는 작업들을 처리한다.

즉, 사용자 목록 검색, 사용자 생성, 사용자 업데이트, 사용자 삭제와 같은 작업들은 모두 Mono나 Flux를 사용하여 비동기적으로 처리된다.

 

이처럼 Mono와 Flux는 리액티브 프로그래밍에서 매우 유용한 리액터 타입이다.

스프링 WebFlux에서는 이러한 리액터 타입을 사용하여 비동기적으로 실행되는 작업을 처리하고, 더 나은 성능과 확장성을 제공한다.

 

이때!
switchIfEmpty()를 사용하지 않으면 Mono나 Flux가 비어있을 때, 기본값이나 대체값이 없는 상태로 반환된다.

이 경우, Mono나 Flux가 비어있다는 것을 나타내는 값, 즉 null 또는 빈 리스트 등이 반환될 수 있다.

예를 들어, findById() 메소드가 Mono<User>를 반환할 때, ID가 id인 사용자를 찾을 수 없는 경우, Mono<User>가 비어있게 된다.

이 경우, Mono<User>가 null을 반환하게 되면 NullPointerException이 발생할 수 있다.

따라서, switchIfEmpty()를 사용하여 Mono<User>가 비어있을 때, 대체값을 반환하도록 설정하는 것이 좋다.

반응형