CHAP17 - Modern-Java-in-Action/Online-Study GitHub Wiki
์ฃผ์ : ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ
RP = Reactive Programming
- ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ์ ์ ์ํ๊ณ ๋ฆฌ์กํฐ๋ธ ๋งค๋ํจ์คํ ๋ฅผ ํ์ธํจ
- ๊ณผ๊ฑฐ์ ์๋ชป๋ ํ์ ์ ์์งํ ๋ฐ์ฑํ๋ฉฐ ์๋ก์ด ๋ฏธ๋๋ฅผ ์ํ ๊ตฌ์ฒด์ ์ฝ์์ ๊ณต๊ฐ์ ์ธ ๋ฐฉ์์ผ๋ก ์ฑ ์์ฑ์ ๋ด์ ๋ฌธ์๋ก์ ์ ์ธํ๋ ๊ฒ
- ์ ํ๋ฆฌ์ผ์ด์ ์์ค, ์์คํ ์์ค์ ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ
- ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ, ์๋ฐ 9ํ๋ก API๋ฅผ์ฌ์ฉํ์์ ์ฝ๋
- ๋๋ฆฌ ์ฌ์ฉ๋๋ ๋ฆฌ์กํฐ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ RxJava ์๊ฐ
- ์ฌ๋ฌ ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ์ ๋ณํํ๊ณ ํฉ์น๋ RxJava ๋์ ์ดํด๋ณด๊ธฐ
- ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ์ ๋์์ ์๊ฐ์ ์ผ๋ก ๋ฌธ์ํํ๋ ๋ง๋ธ ๋ค์ด์ด๊ทธ๋จ
์ค๋๋ ์ํฉ์ด ๋ณํ๋ค.
- ๋น ๋ฐ์ดํฐ
- ๋ง์ ๋ชจ๋ฐ์ผ ๋๋ฐ์ด์ค์ ์์ฒ๊ฐ ๋ฉํฐ์ฝ์ด ํ๋ก์ธ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ฐฐํฌ ํ๊ฒฝ
- 1๋ ๋ด๋ด ๊ฐ๋ฅํ ๊ณ ๊ฐ์ ์๋น์ค ์๊ตฌ
๋งคํํ์์ค. ( Elastic Responsive Resilient Message-driven )
- ์์คํ ์ ์ ์์ ์๋ตํด์ผ ํ๋ค.
- ์์คํ ์ ๋์จํ ๊ฒฐํฉ์ ๋ณด์ฅํ๊ธฐ ์ํด ๊ตฌ์ฑ ์์ ๊ฐ์ ๋น๋๊ธฐ ๋ฉ์์ง ์ ๋ฌ์ ์ฌ์ฉํด์ผ ํ๋ค.
- ์์คํ ์ ๋์ ๋ถํ์์๋ ์๋ต์ฑ์ ์ ์งํด์ผ ํ๋ค.
- ์ผ๋ถ ๊ตฌ์ฑ ์์๊ฐ ์ฅ์ ๊ฐ ๋ฐ์ํด๋ ์์คํ ์ ์๋ต์ ์ ์งํด์ผ ํ๋ค.
์ ์ดํด์๋จ
- ๋ฆฌ์กํฐ๋ธ ์์คํ
- ์ํคํ ์ฒ ์คํ์ผ์ ํ ์ข ๋ฅ
- ์ ํ๋ฆฌ์ผ์ด์ ์ ์กฐ๋ฆฝํ๊ณ ์ํธ์ํต์ ์กฐ์
- ์์ ๋งค๋ํ์คํ ๋ฅผ ๋ฐ๋ผ, ์์ ๋ถํ๊ฐ ์์ผ๋ฉด ์ ๋์ ์ผ๋ก scale-up ํ๋ ์ฑ์ง์ ๊ฐ์ง
- ์ฃผ์ ์์ฑ: ๋ฉ์์ง ์ฃผ๋
- ๋ฆฌ์กํฐ๋ธ ์ ํ๋ฆฌ์ผ์ด์
- ๋น๊ต์ ์งง์ ์๊ฐ ๋์๋ง ์ ์ง๋๋ ๋ฐ์ดํฐ ์คํธ๋ฆผ์ ๊ธฐ๋ฐํ ์ฐ์ฐ์ ์ํํ๋ฉฐ ๋ณดํต ์ด๋ฒคํธ ์ฃผ๋๋ก ๋ถ๋ฅ๋๋ค.
- ์์ฝ
- ๋ฆฌ์กํฐ๋ธ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ชจ์ฌ ์์คํ ์ด ๋๋ ๊ฒ ๊ฐ๋ค.
- ์ค๋ ๋๋ ๋น์ธ๊ณ ๊ทํ ์์์ด๋ค. (ํ ๋นํ๊ณ ํด์ ํ๋ ๊ฒ๋ ๋น์ธ๋ค)
- ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ์ ํ๋ ์์ํฌ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ฐ๋ฐ์๊ฐ ๋ ์ด์ค ์ปจ๋์ , ๋ฐ๋๋ฝ ๊ฐ์ ๊ฐ์ ์ ์์ค์ ๋ฉํฐ์ค๋ ๋ ๋ฌธ์ ๋ฅผ ์ง์ ์ฒ๋ฆฌํ ํ์๊ฐ ์์ด์ง๋ฉด์ ๋น์ฆ๋์ค ์๊ตฌ์ฌํญ ๊ตฌํ์ ๋ ์ง์คํ ์ ์๋ค.
- ์ค๋ ๋ ํ์ ์ชผ๊ฐค๋๋ ๋ธ๋ญ ๋์์ ๋ฃ์ง ์์์ผ ํ๋ค.
- RxJava, Akka ๊ฐ์ ๋ฆฌ์กํฐ๋ธ ํ๋ ์์ํฌ๋ ๋ณ๋๋ก ์ง์ ๋ ์ค๋ ๋ ํ์์ ๋ธ๋ก ๋์์ ์คํ์์ผ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ค.

๋ฆฌ์กํฐ๋ธ ์์คํ ์ ์ฌ๋ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ด ํ ๊ฐ์ ์ผ๊ด์ ์ธ, ํ๋ณตํ ์ ์๋ ํ๋ซํผ์ ๊ตฌ์ฑํ ์ ์๊ฒ ํด์ค ๋ฟ ์๋๋ผ ์ด๋ค ์ ํ๋ฆฌ์ผ์ด์ ์ค ํ๋๊ฐ ์คํจํด๋ ์ ์ฒด ์์คํ ์ ๊ณ์ ์ด์๋ ์ ์๋๋ก ๋์์ฃผ๋ ์ํํธ์จ์ด ์ํคํ ์ฒ๋ค.
- ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ ์ด๋?
- ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ์ ํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค.
- ๋ฌดํ์ ๋น๋๊ธฐ ๋ฐ์ดํฐ๋ฅผ ์์๋๋ก ๊ทธ๋ฆฌ๊ณ ๋ธ๋กํ์ง ์๋ ์ญ์๋ ฅ์ ์ ์ ํด ์ฒ๋ฆฌํ๋ ํ์ค ๊ธฐ์
- ์ญ์๋ ฅ์ด๋?
- ๋ฐํ-๊ตฌ๋ ํ๋กํ ์ฝ์์ ๊ตฌ๋ ์๊ฐ ๋๋ฆฐ ์๋๋ก ์ด๋ฒคํธ๋ฅผ ์๋นํ๋ฉด์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์๋๋ก ๋ณด์ฅํ๋ ์ฅ์น
- ์ฌ์ฉํจ์ผ๋ก์จ
- ์ด๋ฒคํธ๋ฅผ ์์ด๋ฒ๋ฆฌ๋ ๋ฌธ์ ํด๊ฒฐ ๊ฐ๋ฅ
- ์ด๋ฒคํธ ์์ ์ ๋ฆ์ถ๋ ๊ฒ, ๊ฐ๋ฅํ ์์ ๋ ์๋ฆผ๊ธฐ๋ฅ, ๋จ์์ผ ์ฒ๋ฆฌ ์์ธก ์๊ฐ ์๋ฆผ๊ณผ ๊ฐ์ ๊ธฐ๋ฅ์ผ๋ก ์ ์คํธ๋ฆผ ๊ตฌ๋ ์์๊ฒ ์๋ฆด์ ์๋ค.
- ๋น๋๊ธฐ API๋ฅผ ์ด์ฉํ๋ฉด ํ๋์จ์ด ์ฌ์ฉ๋ฅ ์ ๊ทน๋ํํ ์ ์์ง๋ง ๋๋ฆฐ ๋ค์ด์คํธ๋ฆผ ์ปดํฌ๋ํธ์ ๋๋ฌด ํฐ ๋ถํ๋ฅผ ์ค ๊ฐ๋ฅ์ฑ๋ ์๊ธด๋ค. ์ญ์๋ ฅ์ ์ด ๋ฌธ์ ๋ ํด๊ฒฐํ๋ค.
- ํ์ฌ๋ณ ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ ์์ฒด ๊ตฌํ ์ฌ๋ก
- ๋ผ์ดํธ๋ฐด๋ - Akka Stream
- ๋ทํ๋ฆญ์ค - RxJava
- ๋ฆฌ์กํฐ - Pivotal
- ๋ ๋ํ - Vert.x
- Flow API๋?
- ์๋ฐ์์ ์ 4๊ฐ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ต์ ๊ธฐ๋ฅ ์งํฉ์ผ๋ก๋ง ์ฌ์ ์ํ ํ์ค API = Flow API
Flow ํด๋์ค๊ฐ ํฌํจํ๋ 4๊ฐ ์ธํฐํ์ด์ค
// Publisher: ์ด๋ฒคํธ ๋ฐํ ์ํ
@FunctionalInterface
public interface Publisher<T> {
void subscribe(Subscriber<? super T> s);
}
// Subscriber: ์์ ์ Publisher ์๊ฒ ๋ฑ๋ก ์์ฒญํด ์ด๋ฒคํธ ์๋น
// ํธ์ถ ์์ : onSubscribe -> onNext (์ฌ๋ฌ๋ฒ ํธ์ถ ๊ฐ๋ฅ) -> onError ๋๋ onComplete
public interface Subscriber<T> {
void onSubscribe(Subscription s);
void onNext(T t);
void onError(Throwable t);
void onComplete();
}
// Subscription: Publisher์ Subscriber ์ฌ์ด์ ์ ์ด ํ๋ฆ, ์ญ์๋ ฅ์ ๊ด๋ฆฌํ๋ค.
public interface Subscription {
void request(long n);
void cancel();
}
// Processor: ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ์์ ์ฒ๋ฆฌํ๋ ์ด๋ฒคํธ๋ฅผ ๊ฐ๊ณต, ๋ณํํ ๋ ์ฌ์ฉ๋๋ค.
// ๋ค์ด์ค๋ ๋ฉ์์ง๋ฅผ ๋ณํ์์ผ ๋ค์ ๊ตฌ๋
์ ํํ
๋๊ธฐ๊ธฐ ์ํด ์ฌ์ฉ. (์ค๊ฐ์ ์ญํ ์ด๋ฉฐ, ๊ตฌ๋
์์ ๋ฐํ์ ๋ ์ญํ ์ํ)
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> { }
- ์ธ์ Subscriber์ onSubscribe()์ onNext()๊ฐ ์ฌ์ฉ๋ ๊น?
- onSubscribe(): Subscriber๊ฐ Publisher์ ์์ ์ ๋ฑ๋กํ ๋ Publisher๋ ์ฒ์์ผ๋ก onSubscribe ๋ฉ์๋๋ฅผ ํธ์ถํด Subscription ๊ฐ์ฒด๋ฅผ ์ ๋ฌํ ์ ์๋ค.
- onNext(): Publisher๊ฐ ์๋ก์ด ์ด๋ฒคํธ๋ฅผ ์์ฑํ ๋๋ง๋ค ํธ์ถ๋๋ค.
- Subscription์ request()์ cancel() ๋ฉ์๋์ ์ญํ ์?
- request(): Publisher์๊ฒ ์ฃผ์ด์ง ๊ฐ์์ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ์ค๋น๊ฐ ๋์์์ ์๋ฆฌ๋๋ฐ ์ฌ์ฉ
- cancel(): ๊ตฌ๋ ์ทจ์ ์์ฒญ
- ์๋ ์์ฝ
์จ๋ ์ ๋ณด ์ฃผ๊ธฐ์ ์ผ๋ก ๋ฐ์๋ณผ ์ ์๊ฒ ํ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค์ด ๋ณด์
๋ฆฌ์กํฐ๋ธ ์ ํ๋ฆฌ์ผ์ด์ ์๋ช ์ฃผ๊ธฐ ํ์ธํ๊ธฐ

- ์ฌ๊ธฐ ์ฝ๋์์
- Publisher: ํฉํ ๋ฆฌ ๋ฉ์๋๋ก ๋ฐ๋ก ์์ฑ
- Subscriber: TempSubscriber
- Subscription: TempSubscription
- ๊ธฐํ
- TempInfo: ์จ๋ ์ ๋ณด ๋ด๋ ๊ฐ์ฒด
ํน์ ๋์ ์จ๋ ์ ๋ณด ๊ตฌ๋ ํ๊ธฐ
import java.util.concurrent.Flow.*;
public class Main {
public static void main( String[] args ) {
// Subscriber๋ฅผ ์ธ์๋ก ๋ฐ์ Subscriber์ onSubscribe ๋ฉ์๋๋ฅผ ํธ์ถ
getTemperatures( "New York" ).subscribe( new TempSubscriber() );
}
private static Publisher<TempInfo> getTemperatures( String town ) {
// ์๋ ์ฝ๋ ์ต์ํ์ง๊ฐ ์๋ค์...
return subscriber -> subscriber.onSubscribe(
new TempSubscription( subscriber, town ) );
}
}
์จ๋ ์ ๋ณด๋ฅผ ๋ฐ์๋ณผ ์์ ์ธ ๊ตฌ๋ ์
import java.util.concurrent.Flow.*;
public class TempSubscriber implements Subscriber<TempInfo> {
private Subscription subscription;
@Override
public void onSubscribe( Subscription subscription ) {
this.subscription = subscription; // ๊ตฌ๋
์ ์ฅ
subscription.request( 1 ); // 1๋ฒ์งธ ์์ฒญ
}
@Override
public void onNext( TempInfo tempInfo ) {
// Subscription์ด ์ ๋ฌํ ์จ๋๋ฅผ ์ถ๋ ฅํ๊ณ ์ ๋ ํฌํธ๋ฅผ ๋ค์ ์์ฒญ
System.out.println( tempInfo );
subscription.request( 1 );
}
@Override
public void onError( Throwable t ) {
System.err.println(t.getMessage());
}
@Override
public void onComplete() {
System.out.println("Done!");
}
}
์จ๋ ์ ๋ณด๋ฅผ ๋ฐ์๋ณผ ์ ์๋ ๊ตฌ๋ ๊ถ
import java.util.concurrent.Flow.*;
public class TempSubscription implements Subscription {
private final Subscriber<? super TempInfo> subscriber;
private final String town;
public TempSubscription( Subscriber<? super TempInfo> subscriber,
String town ) {
this.subscriber = subscriber;
this.town = town;
}
@Override
public void request( long n ) {
// ์์ฒญํ ์ด๋ฒคํธ ์ ๋งํผ ์ฒ๋ฆฌํด์ค๋ค
for (long i = 0L; i < n; i++) {
try {
subscriber.onNext( TempInfo.fetch( town ) );
} catch (Exception e) {
subscriber.onError( e );
break;
}
}
}
@Override
public void cancel() {
subscriber.onComplete();
}
}
์จ๋ ์ ๋ณด ๊ฐ์ฒด
import java.util.Random;
public class TempInfo {
public static final Random random = new Random();
private final String town;
private final int temp;
public TempInfo(String town, int temp) {
this.town = town;
this.temp = temp;
}
// ํน์ ํ์ด์ ์จ๋๋ฅผ ๋ฆฌํด
public static TempInfo fetch(String town) {
if (random.nextInt(10) == 0)
throw new RuntimeException("Error!");
return new TempInfo(town, random.nextInt(100));
}
@Override
public String toString() {
return town + " : " + temp;
}
public int getTemp() {
return temp;
}
public String getTown() {
return town;
}
}
๊ฒฐ๊ณผ - ๋ด์์ ์จ๋๋ฅผ ๋ค ๋ฒ ์ฑ๊ณต์ ์ผ๋ก ์ ๋ฌํ์ง๋ง ๋ค์ฏ ๋ฒ์งธ์ ์๋ฌ๊ฐ ๋ฐ์
New York :: 44
New York :: 68
New York :: 95
New York :: 30
Error!
์ง๊ธ๊น์ง ๊ฐ๋ฐํ ์ฝ๋์ ์์ ๋ฌธ์ ๊ฐ ์๋ค. ํด์ฆ๋ฅผ ๋ณด๊ณ ์๊ฐํด๋ณด์.
์ง๊ธ๊น์ง ๊ฐ๋ฐํ ์ฝ๋์ ์์ ๋ฌธ์ ๊ฐ ์๋ค. ํ์ง๋ง ์ด ๋ฌธ์ ๋ Tempinfo ํฉํ ๋ฆฌ ๋ฉ์๋ ๋ด์์ ์๋ฌ๋ฅผ ์์๋ก ๋ฐ์์ํค๋ ์ฝ๋ ๋๋ฌธ์ ๊ฐ์ถฐ์ง ์ํ๋ค. ์์๋ก ์๋ฌ๋ฅผ ๋ฐ์์ํค๋ ์ฝ๋๋ฅผ ์์ค ๋ค์ main์ ์ค๋ ์คํํ๋ฉด ์ด๋ค ์ผ์ด ์ผ์ด๋ ๊น?
.
.
.
.
.
.
.
.
- Executor๋ฅผ TempSubscription์ผ๋ก ์ถ๊ฐํ ๋ค์ ๋ค๋ฅธ ์ค๋ ๋์์ TempSubscriber๋ก ์ธ ์์๋ฅผ ์ ๋ฌํ๋ค.
- ์ด๊ฒ ์ดํด ์ ์๋๋ค.
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TempSubscription implements Subscription {
private static final ExecutorService executor =
Executors.newSingleThreadExecutor();
@Override
public void request( long n ) {
// ๋ค๋ฅธ์ค๋ ๋์์ ๋ค์์์๋ฅผ ๊ตฌ๋
์์๊ฒ ๋ณด๋ธ๋ค.
executor.submit( () -> {
for (long i = 0L; i < n; i++) {
try {
subscriber.onNext( TempInfo.fetch( town ) );
} catch (Exception e) {
subscriber.onError( e );
break;
}
}
});
}
}
Processor ์ธํฐํ์ด์ค์ ์ฌ์ฉ๋ฒ๋ ํ์ธํ์
- ๋ชฉ์ : Publisher๋ฅผ ๊ตฌ๋ ํ ๋ค์ ์์ ํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํด ๋ค์ ์ ๊ณตํ๋ ๊ฒ
- Subscriber ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ๋ค๋ฅธ ๋ชจ๋ ๋ฉ์๋๋ ๋จ์ํ ์์ ํ ๋ชจ๋ ์ ํธ๋ฅผ ์ ์คํธ๋ฆผ Subscriber๋ก ์ ๋ฌํ๋ฉฐ Publisher์ subscribe ๋ฉ์๋๋ ์ ์คํธ๋ฆผ Subscriber๋ฅผ Processor๋ก ๋ฑ๋กํ๋ ๋์์ ์ํํ๋ค.
Main: Publisher๋ฅผ ๋ง๋ค๊ณ TempSubscriberB ๊ตฌ๋ ์ํด
import java.util.concurrent.Flow.*;
public class Main {
public static void main( String[] args ) {
getCelsiusTemperatures( "New York" )
.subscribe( new TempSubscriber() );
}
public static Publisher<TempInfo> getCelsiusTemperatures(String town) {
return subscriber -> {
TempProcessor processor = new TempProcessor();
processor.subscribe( subscriber );
processor.onSubscribe( new TempSubscription(processor, town) );
};
}
}
import java.util.concurrent.Flow.*;
// ํ์จ๋ฅผ ์ญ์จ๋ก ๋ณํ
public class TempProcessor implements Processor<TempInfo, TempInfo> {
private Subscriber<? super TempInfo> subscriber;
@Override
public void subscribe( Subscriber<? super TempInfo> subscriber ) {
this.subscriber = subscriber;
}
// ๋ก์ง์ ํฌํจํ๋ ์ ์ผํ ๋ฉ์๋
@Override
public void onNext( TempInfo temp ) {
// ์ญ์จ๋ก ๋ณํํ ๋ค์ TempInfo ๋ฅผ ๋ค์ ์ ์ก
subscriber.onNext( new TempInfo( temp.getTown(),
(temp.getTemp() - 32) * 5 / 9) );
}
@Override
public void onSubscribe( Subscription subscription ) {
// ์
์คํธ๋ฆผ ๊ตฌ๋
์์ ์ ๋ฌ
subscriber.onSubscribe( subscription );
}
@Override
public void onError( Throwable throwable ) {
// ์
์คํธ๋ฆผ ๊ตฌ๋
์์ ์ ๋ฌ
subscriber.onError( throwable );
}
@Override
public void onComplete() {
// ์
์คํธ๋ฆผ ๊ตฌ๋
์์ ์ ๋ฌ
subscriber.onComplete();
}
}
์คํ ์ฝ๋
New York : 10
New York : -12
New York : 23
Error!
- Flow API๊ฐ ๊ตฌํ์ ์ฌ๊ณตํ์ง ์์, ์ฐ๋ฆฌ๊ฐ ์ง์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ค.
- ๋ค๋ฅธ ์ฌ๋ก๋ฅผ ๋ณด๋ฉด, ์๋ฐ๋ List์ ๊ตฌํ์ธ ArrayList๋ฅผ ์ ๊ณตํ๋ค.
- ์ ๊ตฌํ ์ ๊ณต์ ์ํ ๊น?
- ์ด์ : API๋ฅผ ๋ง๋ค ๋น์ Akka, RxJava ๋ฑ ๋ค์ํ ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ์ ์๋ฐ ์ฝ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ด๋ฏธ ์กด์ฌํ๊ธฐ ๋๋ฌธ์ด๋ค
- ์ฆ, ์ด ๋ชจ๋ ๊ธฐ๋ฅ์ ๊ณตํต ๋ถ๋ถ๋ง ๋ด ์๋ด ํ์คํ ์์ ์ ํ ๊ฒ์ด๋ค.
-
RxJava: ๋ฆฌ์กํฐ๋ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ํ ์ข ๋ฅ
-
RxJava ๋ Flow.Publisher ๋ฅผ ๊ตฌํํ๋ ๋ ํด๋์ค๋ฅผ ์ ๊ณต
-
io.reactivex.Flowable
- Pull ๊ธฐ๋ฐ ์ญ์๋ ฅ ๊ธฐ๋ฅ ํฌํจ
- ์ด๋ฏธ Flow API๋ฅผ ํตํด ์ญ์๋ ฅ์ ํ์ธํ์ผ๋ ์๋์ ์๋ต
-
io.reactivex.Observable
- ์ญ์๋ ฅ ์ง์ X
- ๋จ์ํ ๋ง์ฐ์ค ์์ง์ ๊ฐ์ ์ฌ์ฉ์ ์ธํฐํ์ด์ค ์ด๋ฒคํธ์ ์ ํฉ
- ์ด์ : ๋ง์ฐ์ค ์์ง์์ ๋๋ฆฌ๊ฒ ํ๊ฑฐ๋ ๋ฉ์ถ ์ ์๋ฏ์ด ์ญ์๋ ฅ์ ์ ์ฉํ ์ ์๊ธฐ ๋๋ฌธ
-
-
Flow API ์ ๋น๊ต
-
Publisher ์ญํ : Observable
- ์ต์ ๋ฒ๋ธ์ ์ญ์๋ ฅ ์ง์์ ์ํ๋ฏ๋ก, request() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ํ์ ์๋ค.
- Subscription ํด๋์ค ์ด์ฉ์ด ํ์ ์๋ค๋๊ฑฐ ๊ฐ์.
-
Subscriber ์ญํ : Observer
-
์ต์ ๋ฒ๋ ์ถ๊ฐ๋ก Disposable ์ธ์๋ฅผ ๊ฐ๋๋ค.
-
Observer ์ธํฐํ์ด์ค
public interface Observer<T> { void onSubscribe(Disposable d); void onNext(T t); void onError(Throwable t); void onComplete(); }
-
-
-
์ข์ ์์คํ ์ํคํ ์ฒ๋ฅผ ์ํ TIP
- ์ธ๋ถ ์ฌํญ์ ๋
ธ์ถํ์ง ๋ง์.
- ์ฆ, Observable์ ์ถ๊ฐ ๊ตฌ์กฐ๊ฐ ํ์ํ ์ํฉ์์๋ง Observable ์ ์ฌ์ฉํ๊ณ ๊ทธ๋ ์ง ์์ผ๋ฉด Publisher์ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
- ๋น์ทํ ์ฌ๋ก
- ์ ๋ฌํ๋ ๊ฐ์ด ArrayList ์์ ์์ง๋ง ํ๋ผ๋ฏธํฐ ํ์์ List๋ก ์ค์ ํจ์ผ๋ก ๊ตฌํ ์ธ๋ถ์ฌํญ์ ๋ฐ์ผ๋ก ๋ ธ์ถํ์ง ์์ ์ ์๋ค.
- ์ด๋ผ์ผ๋ก์จ, LinkedList๋ก ์ ์ฉ ๊ฐ๋ฅํ๋ค.
- ๋คํ์ฑ
- ์ธ๋ถ ์ฌํญ์ ๋
ธ์ถํ์ง ๋ง์.
-
๋ง๋ธ ๋ค์ด์ด๊ทธ๋จ
- ๋ชจํ๋ค์ ์ํ์ ์ ํ์ํด์ ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ์ ํ๋ฆ์ ๋ณด์ฌ์ค๋ค.

์ง๊ธ๋ถํฐ๋ RxJava์ ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ์ ๊ตฌํ์ ์ด์ฉํด์ ์จ๋ ๋ณด๊ณ ์์คํ ์ ์ ์ํด๋ณด์.
Observable, Flowable ํด๋์ค๋ ๋ค์ํ ์ข ๋ฅ์ ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ์ ํธ๋ฆฌํ๊ฒ ๋ง๋ค ์ ์๋๋ก ์ฌ๋ฌ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค.
- just(): ํ ๊ฐ ์ด์์ ์์๋ฅผ ์ด์ฉํด ์ด๋ฅผ ๋ฐฉ์ถํ๋ Observable๋ก ๋ณํํ๋ค.
- interval(): ํน์ ์๋๋ก ์ด๋ฒคํธ๋ฅผ ๋ฐฉ์ถํ๋ ์ํฉ์ ์ ์ฉํ๋ค.
just() ์ฌ์ฉํ ๊ฐ๋จํ ์์
// Observable์ ๊ตฌ๋
์๋ onNext("first"), onNext("second"), onComplete()์ ์์๋ก ๋ฉ์์ง๋ฅผ ๋ฐ๋๋ค.
Observable<String> strings = Observable.just( "first", "second" );
Disposable disposable = strings.subscribe(System.out::println); // ๊ตฌ๋
ํ๊ธฐ
disposable.dispose(); // ๊ตฌ๋
์ทจ์
System.out.println(disposable.isDisposed());
interval() ์ฌ์ฉ ์
- ์ด ์ฝ๋๋ ํ๋ฆฐํ
์ด ์๋๊ณ ์ข
๋ฃ๋๋ฒ๋ฆฐ๋ค.
- ์ด์ : ๋งค ์ด๋ง๋ค ์ ๋ณด๋ฅผ ๋ฐํํ๋ Observable์ด RxJava์ ์ฐ์ฐ ์ค๋ ๋ ํ ์ฆ ๋ฐ๋ชฌ ์ค๋ ๋์์ ์คํ๋๊ธฐ ๋๋ฌธํ๋ฆฐํ ์ด ์๋๋ค.
- ํด๊ฒฐ: blockingSubscribe() ์ฌ์ฉํ๊ธฐ
// main ํ๋ก๊ทธ๋จ์ ์คํํ์ ๋ง์ ๋ฐ๋ก ์คํํ ์ฝ๋๊ฐ ์์ผ๋ฏ๋ก ๋ฐ๋ก ์ข
๋ฃ๋๊ณ
// ํ๋ก๊ทธ๋จ์ด ์ข
๋ฃ๋์์ผ๋ฏ๋ก ์ด๋ค ๊ฒฐ๊ณผ๋ฅผ ์ถ๋ ฅํ๊ธฐ๋ ์ ์ ๋ฐ๋ชฌ ์ค๋ ๋๋ ์ข
๋ฃ๋๋ฉด์
// ์ด๋ฐ ํ์์ด ์ผ์ด๋๋คใด
Observable<Long> onePerSec = Observable.interval(1, TimeUnit.SECONDS);
onePerSec.subscribe(i -> System.out.println(TempInfo.fetch( "New York" )));
// onePerSec.blockingSubscribe(i -> System.out.println(TempInfo.fetch( "New York" )));
์์ ์ ๋์ด๋๋ฅผ ๋์ฌ๋ณด์.
์จ๋๋ฅผ ์ง์ ์ถ๋ ฅํ์ง ์๊ณ ์ฌ์ฉ์์๊ฒ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ์ ๊ณตํด ๋งค ์ด๋ง๋ค ์จ๋๋ฅผ ๋ฐฉ์ถํ๋ Observable์ ๋ฐํํด๋ณด์.
main ์ฝ๋
// getTemperature ๋ฉ์๋๊ฐ ๋ฐํํ๋ Observable์ TempObserver ๋ฅผ ๊ตฌ๋
์ํจ๋ค.
public static void main(String[] args) {
// ๋งค์ด๋ง๋ค ๋ด์ ์จ๋ ๋ฐฉ์ถํ๋ Oberserverble ์์ฑ
Observable<TempInfo> observable = getTemperature( "New York" );
// Observable์ ๊ฐ์
ํด์ ์จ๋ ์ถ๋ ฅ
observable.blockingSubscribe( new TempObserver() );
}
- ์์ ์ ๋ฆฌ
- Observer๋ฅผ ์๋นํ๋ ํจ์๋ก๋ถํฐ Observable ๋ง๋ค๊ธฐ
- ๋งค์ด ๋ง๋ค ๋ฌดํ์ผ๋ก ์ฆ๊ฐํ๋ ์ผ๋ จ์ long ๊ฐ์ ๋ฐฉ์ถํ๋ Observerble
- ์๋น๋ Observer๊ฐ ํ๊ธฐ๋์ง ์์์ผ๋ฉด ์ด๋ค ์์ ์ ์ํ (์ด์ ์๋ฌ)
- ์จ๋๋ฅผ ๋ค์ฏ๋ฒ ๋ณด๊ณ ํ์ผ๋ฉด ์ต์ ๋ฒ๋ฅผ ์๋ฃํ๊ณ ์คํธ๋ฆผ ์ข ๋ฃ
- ์๋๋ฉด ์จ๋๋ฅผ ์ต์ ๋ฒ๋ก ๋ณด๊ณ
public static Observable<TempInfo> getTemperature(String town) {
return Observable.create(emitter ->
Observable.interval(1, TimeUnit.SECONDS)
.subscribe(i -> {
if (!emitter.isDisposed()) {
// ํธ์์ ๋ค์ฏ ๋ฒ๋ง
if ( i >= 5 ) {
emitter.onComplete();
} else {
try {
emitter.onNext(TempInfo.fetch(town));
} catch (Exception e) {
emitter.onError(e);
}
}
}}));
}
์์ ํ ์จ๋๋ฅผ ์ถ๋ ฅํ๋ Observer
- ์ญ์๋ ฅ์ ์ ๊ณตํ์ง ์์ผ๋, request() ๋ฉ์๋๊ฐ ํ์ ์์ด ๋จ์ํ๋ค.
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
public class TempObserver implements Observer<TempInfo> {
@Override
public void onComplete() {
System.out.println( "Done!" );
}
@Override
public void onError( Throwable throwable ) {
System.out.println( "Got problem: " + throwable.getMessage() );
}
@Override
public void onSubscribe( Disposable disposable ) {
}
@Override
public void onNext( TempInfo tempInfo ) {
System.out.println( tempInfo );
}
}
๊ฒฐ๊ณผ
New York : 69
New York : 26
New York : 85
New York : 94
New York : 29
Done!
RxJava ์์ ๋ฅผ ์กฐ๊ธ ๋ ๋ฐ์ ์์ผ์ ํ ๊ฐ ์ด์์ ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ์ ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์.
Observable์ด ๋ฐฉ์ถํ๋ ์์๋ฅผ ์กฐ์ํ๋ ๋ค์ํ ๋ฐฉ๋ฒ์ ํ์ธํด๋ณด์.
RxJava์ ์ฅ์ : ์คํธ๋ฆผ์ ํฉ์น๊ณ , ๋ง๋ค๊ณ , ๊ฑฐ๋ฅด๋ ๋ฑ์ ํ๋ถํ ๊ธฐ๋ฅ ์ฌ์ฉ ๊ฐ๋ฅ
map() ์ฌ๋ก
// ์ญ์จ๋ฅผ ํ์จ๋ก
public static Observable<TempInfo> getCelsiusTemperature(String town) {
return getTemperature( town )
.map( temp -> new TempInfo( temp.getTown(),
(temp.getTemp() - 32) * 5 / 9) );
}
filter() ์ฌ๋ก
// ํํฐ์ ๋ง์กฑํ๋ Observable๋ค๋ง ๊ฐ์ ธ์จ๋ค.
// ์๋๋ ๋์์ ๊ฑธ๋ฆด ์ํ์ด ์์ ๋ ์๋ ค์ฃผ๋ ๊ฒฝ๊ณ ์์คํ
์ฌ๋ก
public static Observable<TempInfo> getNegativeTemperature(String town) {
return getCelsiusTemperature( town )
.filter( temp -> temp.getTemp() < 0 ); // ์จ๋๊ฐ ์ญ์จ 0๋ ์ดํ์ผ ๋๋ง
}
์ธ ๋์์ ์จ๋๋ฅผ ์ถ๋ ฅํ๋ Main ํด๋์ค
- getCelsiusTemperatures(): ์ฌ๋ฌ ๋์์์ ์จ๋๋ฅผ ๋ฐฉ์ถํ๋ Observable์ ๊ฐ์ง ์ ์๋๋ก ์ฒ๋ฆฌ๋์๋ค.
public class Main {
public static void main(String[] args) {
Observable<TempInfo> observable = getCelsiusTemperatures(
"New York", "Chicago", "San Francisco" );
observable.blockingSubscribe( new TempObserver() );
}
}
- merge ๋ฉ์๋๋ Iterable์ ์ธ์๋ก ๋ฐ์ ๋ง์น ํ ๊ฐ์ Observable ์ฒ๋ผ ๋์ํ๋๋ก ๊ฒฐ๊ณผ๋ฅผ ํฉ์น๋ค.
public static Observable<TempInfo> getCelsiusTemperatures(String... towns) {
return Observable.merge(Arrays.stream(towns)
.map(TempObservable::getCelsiusTemperature)
.collect(toList()));
}
๊ฒฐ๊ณผ
New York : 21
Chicago : 6
San Francisco : -15
New York : -3
Chicago : 12
San Francisco : 5
Got problem: Error!
merge ๋ง๋ธ ๋ค์ด์ด๊ทธ๋จ

- ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ์ ์ฌ์์ ์ด๋ฏธ ์ค๋์ ์ ๋์์ง๋ง ์ต๊ทผ์์์ผ ๊ฐ๊ด๋ฐ๋ ์ค์ด๋ค.
- ๋ฆฌ์กํฐ๋ธ ์ํํธ์จ์ด๋ 4 ๊ฐ์ง ์์ฑ (๋ฐ์์ฑ, ํ๋ณต์ฑ, ํ๋ ฅ์ฑ, ๋ฉ์์ง ์ฃผ๋) ์ ๊ฐ์ ธ์ผ ํ๋ค.
- ๋ฆฌ์กํฐ๋ธ ์์คํ ๊ณผ ๋ฆฌ์กํฐ๋ธ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ฐ๋ ์ฐจ์ด๋ฅผ ์์.
- ๋ฆฌ์กํฐ๋ธ ์คํธ๋ฆผ์์ ์ญ์๋ ฅ์ ์ค์ํ๋ค. (๊ตฌ๋ ์-๋ฐํ์ ์๋ ์ฐจ์ดํด๊ฒฐ)
- RxJava๋ ๋ฆฌ์กํฐ๋ธ ํ๋ก๊ทธ๋๋ฐ ๋๊ตฌ ์ค ๋ํ์ ์ด๋ค. (๊ฐ๋ ฅํ ์ฐ์ฐ์๋ค - filter, map ๋ฑ)
- ํ์คํ๋ ์๋ฐ Flow API ๊ฐ ์๋ค.