스프링 WebFlux에서 Disposable은 Reactor 프로젝트에서 제공하는 인터페이스로, 자원 해제와 관련된 중요한 역할을 한다.
비동기 및 논블로킹 환경에서 자원을 적절하게 해제하고 정리하는 메커니즘을 제공한다.
@FunctionalInterface
public interface Disposable {
void dispose();
default boolean isDisposed() {
return false;
}
public interface Composite extends Disposable {
boolean add(Disposable var1);
default boolean addAll(Collection<? extends Disposable> ds) {
boolean abort = this.isDisposed();
Iterator var3 = ds.iterator();
while(var3.hasNext()) {
Disposable d = (Disposable)var3.next();
if (abort) {
d.dispose();
} else {
abort = !this.add(d);
}
}
return !abort;
}
void dispose();
boolean isDisposed();
boolean remove(Disposable var1);
int size();
}
public interface Swap extends Disposable, Supplier<Disposable> {
boolean update(@Nullable Disposable var1);
boolean replace(@Nullable Disposable var1);
}
}
핵심 메소드는 dispose()이다. dispose()메소드는 해당 Disposable객체가 관리하는 리소스나 작업을 해제하고 정리하도록 지시하는 역할을 한다.
Mono나 Flux같은 Publisher를 subscribe() 메소드로 구독하면 일반적으로 Disposable객체가 반환된다. 이 Disposable객체는 구독을 명시적으로 취소하거나, 구독과 관련된 자원을 해제할 때 사용된다.
Disposable을 사용하여 리소스 라이프사이클을 관리한다.Mono.using()이나 Flux.using()과 같은 리소스 관리 오퍼레이터에 리소스 해제를 위한 Disposable을 반환하거나 리소스가 Disposable을 구현하는 경우 이를 활용하여 자동으로 리소스를 정리할 수 있다.Disposable.composite()와 같은 유틸리티 메소드를 사용하여 여러 Disposable인스턴스를 하나의 Disposable로 묶을 수 있다.dispose()호출로 모든 구성 요소 Disposable을 한 번에 해제할 수 있다.dispose()를 호출하지 않거나, 리액티브 스트림이 정상적으로 완료되지 않는 경우, 구독이 유지되어 관련 리소스(ex: 스레드, 네트워크 연결, 메모리 버퍼)가 해제되지 않고 계속 남아있을 수 있다.Disposable객체를 dispose()하여 깨끗하게 정리하고 예측 가능한 방식으로 종료되도록 돕는다.Disposable은 Subscription 인터페이스와 밀접한 관련이 있다. Subscription 인터페이스에는 cancel() 메소드가 있다.
cancel()과 유사하게 구독을 취소하는 역할도 하지만, Disposable은 좀 더 넓은 의미에서 "자원 해제 및 정리"를 나타내는 인터페이스이다.subscribe()가 반환하는 Disposable은 내부적으로 cancel()을 호출하고 관련된 추가적인 정리 작업을 수행한다.일반적으로 Mono나 Flux를 구독하고 받은 Disposable 인스턴스에 대해 dispose()를 호출하는 것이 구독 취소 및 자원 해제를 위한 권장 방식이다.
@SpringBootTest
public class DisposableTest {
@Test
void dispose() throws InterruptedException {
System.out.println("--- Flux.interval 예제: Disposable을 이용한 자원 해제 ---");
// 1초마다 숫자를 발행하는 Flux 생성
Flux<Long> tickingFlux = Flux.interval(Duration.ofSeconds(1));
// Flux를 구독하고 Disposable 객체 받기
// 이 시점부터 1초마다 숫자가 출력되기 시작
Disposable subscription = tickingFlux.subscribe(
data -> System.out.println("받은 데이터: " + data),
error -> System.err.println("에러 발생: " + error),
() -> System.out.println("완료 시그널") // 이 경우 interval은 무한 스트림이므로 완료 시그널은 오지 않음
);
System.out.println("구독 시작. 5초 후에 구독을 해제합니다...");
// 메인 스레드는 5초 동안 대기
Thread.sleep(5000);
// 5초 후, subscription.dispose()를 호출하여 구독을 취소하고 내부 리소스(타이머 스레드) 해제
if (!subscription.isDisposed()) { // 이미 해제되었는지 확인
subscription.dispose();
System.out.println("구독이 성공적으로 해제되었습니다. 더 이상 데이터가 오지 않습니다.");
} else {
System.out.println("구독이 이미 해제된 상태입니다.");
}
}
}