chapter10 sijun - JAVA-JIKIMI/SPRING-IN-ACTION-5 GitHub Wiki

Chapter 10. ๋ฆฌ์•กํ„ฐ ๊ฐœ์š”

์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ ๊ฐœ๋ฐœ์˜ ๋‘๊ฐ€์ง€ ํ˜•ํƒœ

  • ๋ช…๋ นํ˜• - ์ˆœ์ฐจ์ ์œผ๋กœ ์—ฐ์†๋˜๋Š” ์ž‘์—…์ด๋ฉฐ, ๊ฐ ์ž‘์—…์€ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ ๊ทธ๋ฆฌ๊ณ  ์ด์ „ ์ž‘์—… ๋‹ค์Œ์— ์‹คํ–‰๋œ๋‹ค. ๋ฐ์ดํ„ฐ๋Š” ๋ชจ์•„์„œ ์ฒ˜๋ฆฌ๋˜๊ณ  ์ด์ „ ์ž‘์—…์ด ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ๋๋‚ธ ํ›„์— ๋‹ค์Œ ์ž‘์—…์œผ๋กœ ๋„˜์–ด ๊ฐˆ ์ˆ˜ ์žˆ๋‹ค
  • ๋ฆฌ์•กํ‹ฐ๋ธŒ - ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์ผ๋ จ์˜ ์ž‘์—…๋“ค์ด ์ •์˜๋˜์ง€๋งŒ, ์ด ์ž‘์—…๋“ค์€ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐ ์ž‘์—…์€ ๋ถ€๋ถ„ ์ง‘ํ•ฉ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ฒ˜๋ฆฌ๊ฐ€ ๋๋‚œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์Œ ์ž‘์—…์— ๋„˜๊ฒจ์ฃผ๊ณ  ๋‹ค๋ฅธ ๋ถ€๋ถ„ ์ง‘ํ•ฉ์˜ ๋ฐ์ดํ„ฐ๋กœ ๊ณ„์† ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋‹ค.

10.1 ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ดํ•ดํ•˜๊ธฐ

๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ๋ช…๋ นํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ๋Œ€์•ˆ์ด ๋˜๋Š” ํŒจ๋Ÿฌ๋‹ค์ž„์ด๋‹ค. ๋ช…๋ นํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•œ๊ณ„๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋Ÿฐ ํ•œ๊ณ„๋ฅผ ์ดํ•ดํ•˜๋ฉด ๋ฆฌ์•กํ‹ฐ๋ธŒ ๋ชจ๋ธ์˜ ์žฅ์ ์„ ๋” ํ™•์‹คํ•˜๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ช…๋ นํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํŠน์ง•

๋ช…๋ นํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์”ฉ ์ˆœ์„œ๋Œ€๋กœ ์ง„ํ–‰๋œ๋‹ค. ๊ทธ๋ ‡๊ธฐ์—, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋ฐ์ดํ„ฐ๋ฅผ ์“ฐ๊ฑฐ๋‚˜ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ๊ณผ ๊ฐ™์€ ๊ฒƒ์ด๋ผ๋ฉด ์ด ์ž‘์—…์ด ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์•„๋ฌด ๊ฒƒ๋„ ํ•  ์ˆ˜ ์—†๋‹ค. ๋”ฐ๋ผ์„œ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์Šค๋ ˆ๋“œ๋Š” ์ฐจ๋‹จ๋˜๋ฉฐ ์ด๋Š” ๋‚ญ๋น„๊ฐ€ ๋œ๋‹ค.

๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํŠน์ง•

์ด์— ๋ฐ˜ํ•ด ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ํ•จ์ˆ˜์ ์ด๋ฉด์„œ ์„ ์–ธ์ ์ด๋‹ค. ์ฆ‰, ์ˆœ์ฐจ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜๋Š” ์ž‘์—… ๋‹จ๊ณ„๋ฅผ ๋‚˜ํƒ€๋‚ธ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฐ์ดํ„ฐ๊ฐ€ ํ˜๋Ÿฌ๊ฐ€๋Š” ํŒŒ์ดํ”„๋ผ์ธ์ด๋‚˜ ์ŠคํŠธ๋ฆผ์„ ํฌํ•จํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด๋Ÿฐ ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์€ ๋ฐ์ดํ„ฐ ์ „์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ณ  ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์„ ๋•Œ๋งˆ๋‹ค ์ฒ˜๋ฆฌ๋˜๋ฏ€๋กœ ์‚ฌ์‹ค์ƒ ์ž…๋ ฅ๋˜๋Š” ๋ฐ์ดํ„ฐ๋Š” ๋ฌดํ•œํ•  ์ˆ˜ ์žˆ๋‹ค.

10.1.1 ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ ์ •์˜ํ•˜๊ธฐ

๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์€ ๋„ทํ”Œ๋ฆญ์Šค, ๋ผ์ดํŠธ๋ฒค๋“œ, ํ”„๋ณดํƒˆ์˜ ์—”์ง€๋‹ˆ์–ด๋“ค์— ์˜ํ•ด 2013๋…„ ๋ง์— ์‹œ์ž‘๋˜์—ˆ๋‹ค. ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์€ ์ฐจ๋‹จ๋˜์ง€ ์•Š๋Š” ๋ฐฑ ํ”„๋ ˆ์…”๋ฅผ ๊ฐ€์ง€๋Š” ๋น„๋™๊ธฐ ์ŠคํŠธ๋ฆผ ์ฒ˜๋ฆฌ์˜ ํ‘œ์ค€์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ๋ชฉ์ ์ด๋‹ค.

๋ฐฑ ํ”„๋ ˆ์…”: ๋ฐ์ดํ„ฐ๋ฅผ ์†Œ๋น„ํ•˜๋Š” ์ปจ์Šˆ๋จธ๊ฐ€ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋งŒํผ์œผ๋กœ ์ „๋‹ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ œํ•œํ•จ์œผ๋กœ์จ ์ง€๋‚˜์น˜๊ฒŒ ๋น ๋ฅธ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋กœ๋ถ€ํ„ฐ์˜ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ ํญ์ฃผ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜๋‹จ์ด๋‹ค.

๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์€ 4๊ฐœ์˜ ์ธํ„ฐํŽ˜์ด์Šค์ธ Publisher(๋ฐœํ–‰์ž), Subscriber(๊ตฌ๋…์ž), Subscription(๊ตฌ๋…), Processor(ํ”„๋กœ์„ธ์„œ)๋กœ ์š”์•ฝํ•  ์ˆ˜ ์žˆ๋‹ค.

Publisherโ†’(0๊ฐœ ์ด์ƒ์˜ Processor)โ†’Subscriber ๊ตฌ์กฐ

/**
Publisher interface
	subscribe() - Subscriber๊ฐ€ Publisher๋ฅผ ๊ตฌ๋… ์‹ ์ฒญํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ
**/
public interface Publisher<T> {
	void subscribe(Subscriber<? super T> subscriber);
}
/**
Subscriber interface
	onSubscribe() - ์ฒซ๋ฒˆ์งธ ์ˆ˜์‹  ์š”์ฒญ์„ ์œ„ํ•œ ๋ฉ”์„œ๋“œ๋กœ ์ธ์ž๋กœ Subscription์„ ์ „๋‹ฌํ•œ๋‹ค
	onNext() - Subscribe๊ฐ€ ๋ฐ์ดํ„ฐ ์š”์ฒญ์ด ์™„๋ฃŒ๋˜๋ฉด ์ถ”๊ฐ€๋กœ
						 Publisher์—๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๋Š” ๋ฉ”์„œ๋“œ
	onError() - ์—๋Ÿฌ ๋ฐœ์ƒ์‹œ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์„œ๋“œ
	onComplete() - Publisher๊ฐ€ ์ž‘์—… ์™„๋ฃŒ ํ›„ ํ˜ธ์ถœํ•˜์—ฌ
								 Subscriber์—๊ฒŒ ์ž‘์—… ์™„๋ฃŒ ์—ฌ๋ถ€๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ๋ฉ”์„œ๋“œ
**/
public interface Subscriber<T> {
	void onSubscribe(Subscription sub);
	void onnext(T item);
	void onError(Throwable ex);
	void onComplete();
}
/**
Subscription interface
	request() - Subscriber๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ์š”์ฒญํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”์„œ๋“œ
	cancel() - Subscriber๊ฐ€ ๊ตฌ๋… ์ทจ์†Œ ์š”์ฒญ์„ ์œ„ํ•œ ๋ฉ”์„œ๋“œ
**/
public interface Subscription {
	void request(long n);
	void cancel();
}
/**
Subscriber์™€ Publisher๋ฅผ ๊ฒฐํ•ฉํ•œ ์ธํ„ฐํŽ˜์ด์Šค
**/
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> {}

ํ•˜์ง€๋งŒ, ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์ŠคํŠธ๋ฆผ์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์—†๋‹ค. ์ด์— ๋”ฐ๋ผ ํ”„๋กœ์ ํŠธ ๋ฆฌ์•กํ„ฐ์—์„œ๋Š” ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์„ ๊ตฌ์„ฑํ•˜๋Š” API๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์˜€๋‹ค. ์ด๋ฒˆ ์žฅ์˜ ๋‚˜๋จธ์ง€์—์„œ๋Š” ํ”„๋กœ์ ํŠธ ๋ฆฌ์•กํ„ฐ๋ฅผ ์‚ดํŽด๋ณผ ๊ฒƒ์ด๋‹ค.

10.2 ๋ฆฌ์•กํ„ฐ ์‹œ์ž‘ํ•˜๊ธฐ

๋ช…๋ นํ˜• ์ฝ”๋“œ vs ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ฝ”๋“œ

๋ช…๋ นํ˜•

์Šค๋ ˆ๋“œ์—์„œ ํ•œ ๋‹จ๊ณ„์”ฉ ์ฐจ๋ก€๋Œ€๋กœ ์‹คํ–‰๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐ ๋‹จ๊ณ„๊ฐ€ ์™„๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ์ด๋™ํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ์‹คํ–‰ ์ค‘์ธ ์Šค๋ ˆ๋“œ๋ฅผ ๋ง‰๋Š”๋‹ค.

String name ="Craig";
String capitalName = name.toUpperCase();
String greeting = "Hello, " + capitalName + "!";
System.out.println(greeting);

๋ฆฌ์•กํ‹ฐ๋ธŒ

๋ฆฌ์•กํ‹ฐ๋ธŒ ์ฝ”๋“œ๊ฐ€ ๋‹จ๊ณ„๋ณ„๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ, ์‹ค์ œ๋กœ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์ „๋‹ฌ๋˜๋Š” ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฐ ๋‹จ๊ณ„์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ํ•˜๋“  ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค. ๋˜ํ•œ, ๊ฐ ์˜คํผ๋ ˆ์ด์…˜์€ ๊ฐ™์€ ์Šค๋ ˆ๋“œ๋กœ ์‹คํ–‰๋˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.

Mono.just("Craig")
		.map(n -> n.toUpperCase())
		.map(cn -> "Hello, " + cn + "!")
		.subscribe(System.out:println);

just() ์˜คํผ๋ ˆ์ด์…˜์€ ์ฒซ ๋ฒˆ์งธ ๊ฒƒ์„ ์ƒ์„ฑํ•œ๋‹ค. ์ฒซ๋ฒˆ์จฐ Mono๊ฐ€ ๊ฐ’์„ ๋ฐฉ์ถœํ•˜๋ฉด ์ด ๊ฐ’์ด ์ฒซ ๋ฒˆ์งธ map() ์˜คํผ๋ ˆ์ด์…˜์— ์ „๋‹ฌ๋˜์–ด ๋Œ€๋ฌธ์ž๋กœ ๋ณ€๊ฒฝ๋˜๊ณ  ๋‹ค๋ฅธ mono๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ์ƒ์„ฑ๋œ ๋‘ ๋ฒˆ์งธ Mono๊ฐ€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐฉ์ถœํ•˜๋ฉด ์ด ๋ฐ์ดํ„ฐ๊ฐ€ ๋‘ ๋ฒˆ์งธ map()์— ์ „๋‹ฌ๋˜์–ด ๋ฌธ์ž์—ด ๊ฒฐํ•ฉ์ด ์ˆ˜ํ–‰๋˜๋ฉฐ, ์ด ๊ฒฐ๊ณผ๋Š” ์„ธ ๋ฒˆ์งธ Mono๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋์œผ๋กœ subscribe() ํ˜ธ์ถœ์—์„œ๋Š” ์„ธ ๋ฒˆ์งธ Mono๋ฅผ ๊ตฌ๋…ํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์‹ ํ•˜๊ณ  ์ถœ๋ ฅํ•œ๋‹ค.

Mono์™€ Flux๋Š” ๋ฆฌ์•กํ‹ฐ๋ธŒ์˜ ๋‘ ๊ฐ€์ง€ ํ•ต์‹ฌ ํƒ€์ž…์ด๋‹ค.๋‘ ๊ฐœ ๋ชจ๋‘ ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์˜ Publisher ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด๋‹ค.

Mono: ํ•˜๋‚˜์˜ ๋ฐ์ดํ„ฐ ํ•ญ๋ชฉ๋งŒ ๊ฐ–๋Š” ๋ฐ์ดํ„ฐ์…‹์— ์ตœ์ ํ™”๋œ ๋ฆฌ์•กํ‹ฐ๋ธŒ ํƒ€์ž…

Flux: 0, 1 ๋˜๋Š” ๋‹ค์ˆ˜์˜(๋ฌดํ•œ์ผ ์ˆ˜ ์žˆ๋Š”) ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ–๋Š” ํŒŒ์ดํ”„๋ผ์ธ

10.2.1 ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”Œ๋กœ์šฐ์˜ ๋‹ค์ด์–ด๊ทธ๋žจ

๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”Œ๋กœ์šฐ๋Š” ๋งˆ๋ธ” ๋‹ค์ด์–ด๊ทธ๋žจ(marble diagram)์œผ๋กœ ๋‚˜ํƒ€๋‚ด๊ณค ํ•œ๋‹ค.

  • ์ œ์ผ ์œ— ๋ถ€๋ถ„ - Flux๋‚˜ Mono๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋˜๋Š” ๋ฐ์ดํ„ฐ์˜ ํƒ€์ž„๋ผ์ธ
  • ์ค‘์•™ ๋ถ€๋ถ„ - ์˜คํผ๋ ˆ์ด์…˜
  • ์ œ์ผ ๋ฐ‘ ๋ถ€๋ถ„ - Flux๋‚˜ Mono์˜ ํƒ€์ž„๋ผ์ธ

image

image

10.2.2 ๋ฆฌ์•กํ„ฐ ์˜์กด์„ฑ ์ถ”๊ฐ€ํ•˜๊ธฐ

<!-- ๋ฆฌ์•กํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ -->
<dependency>
	<groupId>io.projectreactor</groupId>
	<artifactId>reactor-core</artifactId>
</dependency>

<!-- ๋ฆฌ์•กํ„ฐ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ -->
<dependency>
	<groupId>io.projectreactor</groupId>
	<artifactId>reactor-test</artifactId>
	<scope>test</scope>
</dependency>

10.3 ๋ฆฌ์•กํ‹ฐ๋ธŒ ์˜คํผ๋ ˆ์ด์…˜ ์ ์šฉํ•˜๊ธฐ

Flux์™€ Mono๋Š” ๋ฆฌ์•กํ„ฐ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฐ€์žฅ ํ•ต์‹ฌ์ ์ธ ๊ตฌ์„ฑ ์š”์†Œ์ด๋‹ค. ์ด ๋‘๊ฐ€์ง€๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒŒ์ดํ”„๋ผ์ธ์„ ์ƒ์„ฑํ•˜๋ฉฐ, ์ด ๋‘๊ฐ€์ง€ ๋‚ด์—๋Š” 500๊ฐœ ์ด์ƒ์˜ ์˜คํผ๋ ˆ์ด์…˜์ด ์žˆ๋‹ค.

  • ์ƒ์„ฑ ์˜คํผ๋ ˆ์ด์…˜ (creation)
  • ์กฐํ•ฉ ์˜คํผ๋ ˆ์ด์…˜ (combination)
  • ๋ณ€ํ™˜ ์˜คํผ๋ ˆ์ด์…˜ (transformation)
  • ๋กœ์ง ์˜คํผ๋ ˆ์ด์…˜ (logic)

10.3.1 ๋ฆฌ์•กํ‹ฐ๋ธŒ ํƒ€์ž… ์ƒ์„ฑํ•˜๊ธฐ

๊ฐ์ฒด๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑํ•˜๊ธฐ

@Test
public void createAFlux_just() {
	Flux<String> fruitFlux = Flux
			.just("Apple", "Orange", "Grape", "Banana", "Strawberry");
}
fruitFlux.subscribe(
	f->System.out.println("Here's some fruit: " + f)
};
@Test
public void createAFlux_just() {
	Flux<String> fruitFlux = Flux
		.just("Apple", "Orange", "Grape", "Banana", "Strawberry");
  
	StepVerifier.create(fruitFlux)
		.expectNext("Apple")
		.expectNext("Orange")
		.expectNext("Grape")
		.expectNext("Banana")
		.expectNext("Strawberry")
		.verifyComplete();
}	

์ปฌ๋ ‰์…˜์œผ๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑํ•˜๊ธฐ

Flux๋Š” ๋ฐฐ์—ด, Iterable ๊ฐ์ฒด, ์ž๋ฐ” Stream ๊ฐ์ฒด๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ๋‹ค.

@Test
public void createAFlux_fromArray() {
  String[] fruits = new String[] {
      "Apple", "Orange", "Grape", "Banana", "Strawberry" };
  
	// fromArray()๋ฅผ ํ™œ์šฉํ•œ Flux ์ƒ์„ฑ
  Flux<String> fruitFlux = Flux.fromArray(fruits);
  
  StepVerifier.create(fruitFlux)
      .expectNext("Apple")
      .expectNext("Orange")
      .expectNext("Grape")
      .expectNext("Banana")
      .expectNext("Strawberry")
      .verifyComplete();
}
@Test
public void createAFlux_fromIterable() {
  List<String> fruitList = new ArrayList<>();
  fruitList.add("Apple");
  fruitList.add("Orange");
  fruitList.add("Grape");
  fruitList.add("Banana");
  fruitList.add("Strawberry");
  
	// fromIterable()๋ฅผ ํ™œ์šฉํ•œ Flux ์ƒ์„ฑ
  Flux<String> fruitFlux = Flux.fromIterable(fruitList);
  
  StepVerifier.create(fruitFlux)
      .expectNext("Apple")
      .expectNext("Orange")
      .expectNext("Grape")
      .expectNext("Banana")
      .expectNext("Strawberry")
      .verifyComplete();
}
@Test
public void createAFlux_fromStream() {
 Stream<String> fruitStream = 
      Stream.of("Apple", "Orange", "Grape", "Banana", "Strawberry");
 
 // fromStream()์„ ํ™œ์šฉํ•œ Flux ์ƒ์„ฑ
 Flux<String> fruitFlux = Flux.fromStream(fruitStream);
  
 StepVerifier.create(fruitFlux)
     .expectNext("Apple")
     .expectNext("Orange")
     .expectNext("Grape")
     .expectNext("Banana")
     .expectNext("Strawberry")
     .verifyComplete();
}

๋ฐ์ดํ„ฐ ์—†์ด ๋งค๋ฒˆ ์ƒˆ ๊ฐ’์œผ๋กœ ์ˆซ์ž๋ฅผ ๋ฐฉ์ถœํ•˜๋Š” Flux๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.

  1. range()๋ฅผ ํ™œ์šฉํ•œ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ

    @Test
    public void createAFlux_range() {
     Flux<Integer> rangeFlux = 
         Flux.range(1, 5);
     
     StepVerifier.create(intervalFlux)
         .expectNext(1)
         .expectNext(2)
         .expectNext(3)
         .expectNext(4)
         .expectNext(5)
         .verifyComplete();
    }

    image

  2. interval()๋ฅผ ํ™œ์šฉํ•œ ๋ฐ์ดํ„ฐ ์ƒ์„ฑ

    ์‹œ์ž‘ ๊ฐ’๊ณผ ์ข…๋ฃŒ ๊ฐ’๋Œ€์‹  ๊ฐ’์ด ๋ฐฉ์ถœ๋˜๋Š” ์‹œ๊ฐ„ ๊ฐ„๊ฒฉ์ด๋‚˜ ์ฃผ๊ธฐ๋ฅผ ์ง€์ •ํ•œ๋‹ค.

    @Test
    public void createAFlux_interval() {
     Flux<Long> intervalFlux = 
         Flux.interval(Duration.ofSeconds(1))
             .take(5);
     
     StepVerifier.create(intervalFlux)
         .expectNext(0L)
         .expectNext(1L)
         .expectNext(2L)
         .expectNext(3L)
         .expectNext(4L)
         .verifyComplete();
    }

    image

10.3.2 ๋ฆฌ์•กํ‹ฐ๋ธŒ ํƒ€์ž… ์กฐํ•ฉํ•˜๊ธฐ

๋‘ ๊ฐœ ์ด์ƒ์˜ ๋ฆฌ์•กํ‹ฐ๋ธŒ ํƒ€์ž…์œผ๋กœ ๊ฒฐํ•ฉ์ด๋‚˜ ๋ถ„ํ• ํ•˜๋Š” ์˜คํผ๋ ˆ์ด์…˜

๋ฆฌ์•กํ‹ฐ๋ธŒ ํƒ€์ž… ๊ฒฐํ•ฉํ•˜๊ธฐ

๋‘ ๊ฐœ์˜ Flux ์ŠคํŠธ๋ฆผ์„ mergeWith() operation์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒฐํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.

@Test
public void mergeFluxes() {
  
  // Flux๋Š” ๊ฐ€๋Šฅํ•œ ๋นจ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐฉ์ถœํ•œ๋‹ค.
  // ๋ฒˆ๊ฐˆ์•„ ๊ตฌ๋…ํ•จ์„ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด delayElements๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.
  
  Flux<String> characterFlux = Flux
      .just("Garfield", "Kojak", "Barbossa")
      .delayElements(Duration.ofMillis(500));
  Flux<String> foodFlux = Flux
      .just("Lasagna", "Lollipops", "Apples")
      .delaySubscription(Duration.ofMillis(250))
      .delayElements(Duration.ofMillis(500));
  
  Flux<String> mergedFlux = characterFlux.mergeWith(foodFlux);

  StepVerifier.create(mergedFlux)
      .expectNext("Garfield")
      .expectNext("Lasagna")
      .expectNext("Kojak")
      .expectNext("Lollipops")
      .expectNext("Barbossa")
      .expectNext("Apples")
      .verifyComplete();
}

image

mergeWith()๋Š” Flux๋“ค์˜ ๊ฐ’์ด ์™„๋ฒฝํ•˜๊ฒŒ ๋ฒˆ๊ฐˆ์•„ ๋ฐฉ์ถœ๋˜๊ฒŒ ๋ณด์žฅํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ํ•„์š”ํ•˜๋‹ค๋ฉด zip() ์˜คํผ๋ ˆ์ด์…˜์„ ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

zip() ์˜คํผ๋ ˆ์ด์…˜์€ ๋ฒˆ๊ฐˆ์•„ ๊ฐ€์ ธ์™€ ์ƒˆ๋กœ์šด flux๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

@Test
  public void zipFluxes() {
    Flux<String> characterFlux = Flux
        .just("Garfield", "Kojak", "Barbossa");
    Flux<String> foodFlux = Flux
        .just("Lasagna", "Lollipops", "Apples");
    
    Flux<Tuple2<String, String>> zippedFlux = 
        Flux.zip(characterFlux, foodFlux);
    
    StepVerifier.create(zippedFlux)
          .expectNextMatches(p -> 
              p.getT1().equals("Garfield") && 
              p.getT2().equals("Lasagna"))
          .expectNextMatches(p -> 
              p.getT1().equals("Kojak") && 
              p.getT2().equals("Lollipops"))
          .expectNextMatches(p -> 
              p.getT1().equals("Barbossa") && 
              p.getT2().equals("Apples"))
          .verifyComplete();
  }

zippedFlux๋กœ๋ถ€ํ„ฐ ๋ฐฉ์ถœ๋˜๋Š” ๊ฐ ํ•ญ๋ชฉ์€ Tuple2(๋‘ ๊ฐœ์˜ ๋‹ค๋ฅธ ๊ฐ์ฒด๋ฅผ ์ „๋‹ฌํ•˜๋Š” ์ปจํ…Œ์ด๋„ˆ ๊ฐ์ฒด), ๊ฐ ์†Œ์Šค Flux๊ฐ€ ์ˆœ์„œ๋Œ€๋กœ ๋ฐฉ์ถœํ•˜๋Š” ํ•ญ๋ชฉ์„ ํฌํ•จํ•œ๋‹ค.

image

๋งŒ์ผ Tuple2๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ํƒ€์ž…์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ zip()์—๊ฒŒ ์ œ๊ณตํ•˜๋ฉด ๋œ๋‹ค

@Test
  public void zipFluxesToObject() {
    Flux<String> characterFlux = Flux
        .just("Garfield", "Kojak", "Barbossa");
    Flux<String> foodFlux = Flux
        .just("Lasagna", "Lollipops", "Apples");
    
    Flux<String> zippedFlux = 
        Flux.zip(characterFlux, foodFlux, (c, f) -> c + " eats " + f);
    
    StepVerifier.create(zippedFlux)
          .expectNext("Garfield eats Lasagna")
          .expectNext("Kojak eats Lollipops")
          .expectNext("Barbossa eats Apples")
          .verifyComplete();
  }

๋จผ์ € ๊ฐ’์„ ๋ฐฉ์ถœํ•˜๋Š” ๋ฆฌ์•กํ‹ฐ๋ธŒ ํƒ€์ž… ์„ ํƒํ•˜๊ธฐ

๋‘ ๊ฐœ์˜ Flux๋ฅผ ๊ฒฐํ•ฉํ•˜๋Š” ๋Œ€์‹  ๋จผ์ € ๊ฐ’์„ ๋ฐฉ์ถœํ•˜๋Š” ์†Œ์Šค Flux์˜ ๊ฐ’์„ ๋ฐœํ–‰ํ•˜๋Š” Flux๋Š” first() ์˜คํผ๋ ˆ์ด์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

image

@Test
public void firstFlux() {
  // delay needed to "slow down" the slow Flux
  
  Flux<String> slowFlux = Flux.just("tortoise", "snail", "sloth")
        .delaySubscription(Duration.ofMillis(100));
  Flux<String> fastFlux = Flux.just("hare", "cheetah", "squirrel");
  
  Flux<String> firstFlux = Flux.first(slowFlux, fastFlux);
  
  StepVerifier.create(firstFlux)
      .expectNext("hare")
      .expectNext("cheetah")
      .expectNext("squirrel")
      .verifyComplete();
}

10.3.3 ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์˜ ๋ณ€ํ™˜๊ณผ ํ•„ํ„ฐ๋ง

๋ฆฌ์•กํ‹ฐ๋ธŒ ํƒ€์ž…์œผ๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ ํ•„ํ„ฐ๋งํ•˜๊ธฐ

์•ž์—์„œ ์›ํ•˜๋Š” ๊ฐœ์ˆ˜์˜ ํ•ญ๋ชฉ์„ ๋ฌด์‹œํ•˜๋Š” ๊ฒƒ์€ skip() ์˜คํผ๋ ˆ์ด์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค.

image

@Test
public void skipAFew() {
  Flux<String> countFlux = Flux.just(
      "one", "two", "skip a few", "ninety nine", "one hundred")
      .skip(3);
 
  StepVerifier.create(countFlux)
      .expectNext("ninety nine", "one hundred")
      .verifyComplete();
}

image

ํŠน์ • ์‹œ๊ฐ„์ด ์ง€๋‚œ ํ›„์— ์˜ค๋Š” ๋ฐ์ดํ„ฐ๋กœ Flux๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด์„  skip() ์•ˆ์— Duration์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

@Test
public void skipAFewSeconds() {
  Flux<String> countFlux = Flux.just(
      "one", "two", "skip a few", "ninety nine", "one hundred")
      .delayElements(Duration.ofSeconds(1))
      .skip(Duration.ofSeconds(4));
 
  StepVerifier.create(countFlux)
      .expectNext("ninety nine", "one hundred")
      .verifyComplete();
}

๋ฐ˜๋Œ€๋กœ ํŠน์ • ๊ฐœ์ˆ˜๋งŒํผ๋งŒ ๋จผ์ € ๋ฐ›๊ณ  ์‹ถ๋‹ค๋ฉด take()๋ฅผ ํŠน์ • ์‹œ๊ฐ„๋™์•ˆ์˜ ๋ฐ์ดํ„ฐ๋งŒ ์‚ฌ์šฉํ•ด์„œ flux๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด์„  take(Duration)์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

@Test
  public void take() {
    Flux<String> nationalParkFlux = Flux.just(
        "Yellowstone", "Yosemite", "Grand Canyon", "Zion", "Acadia")
        .take(3);
   
    StepVerifier.create(nationalParkFlux)
        .expectNext("Yellowstone", "Yosemite", "Grand Canyon")
        .verifyComplete();
  }
  
  @Test
  public void takeForAwhile() {
    Flux<String> nationalParkFlux = Flux.just(
        "Yellowstone", "Yosemite", "Grand Canyon", "Zion", "Grand Teton")
        .delayElements(Duration.ofSeconds(1))
        .take(Duration.ofMillis(3500));
   
    StepVerifier.create(nationalParkFlux)
        .expectNext("Yellowstone", "Yosemite", "Grand Canyon")
        .verifyComplete();
  }

image

image

๋ฆฌ์•กํ‹ฐ๋ธŒ ๋ฐ์ดํ„ฐ ๋งคํ•‘ํ•˜๊ธฐ

Flux๋‚˜ Mono์— ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ์˜คํผ๋ ˆ์ด์…˜ ์ค‘ ํ•˜๋‚˜๋Š” ๋ฐœํ–‰๋œ ํ•ญ๋ชฉ์„ ๋‹ค๋ฅธ ํ˜•ํƒœ๋‚˜ ํƒ€์ž…์œผ๋กœ ๋งคํ•‘(๋ณ€ํ™˜)ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๋‹ค๋ฅธ ํ˜•ํƒœ๋‚˜ ํƒ€์ž…์œผ๋กœ ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•ด map()๊ณผ flatMap() ์˜คํผ๋ ˆ์ด์…˜์„ ์‚ฌ์šฉํ•œ๋‹ค.

image

@Test
  public void map() {
    Flux<Player> playerFlux = Flux
      .just("Michael Jordan", "Scottie Pippen", "Steve Kerr")
      .map(n -> {
        String[] split = n.split("\\s");
        return new Player(split[0], split[1]);
      });
    
    StepVerifier.create(playerFlux)
        .expectNext(new Player("Michael", "Jordan"))
        .expectNext(new Player("Scottie", "Pippen"))
        .expectNext(new Player("Steve", "Kerr"))
        .verifyComplete();
  }

map()์„ ํ™œ์šฉํ•˜๋ฉด ๋งคํ•‘ ์ˆ˜ํ–‰ ๋ฐฉ์‹์ด ๋™๊ธฐ์ ์œผ๋กœ ์ˆ˜ํ–‰๋œ๋‹ค. ๋”ฐ๋ผ์„œ, ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋ ค๋ฉด flatMap()์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

image

๋‹จ์ˆœํžˆ flatMap()์„ ์‚ฌ์šฉํ•˜๋ฉด ๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋œ๋‹ค. subscribeOn()์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌ๋…์ด ๋™์‹œ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์ง€์ •ํ–ˆ๋‹ค. (๋™์‹œ์„ฑ ๋ชจ๋ธ์„ subscribeOn()์˜ ์ธ์ž๋กœ ์ง€์ •ํ•˜์˜€๋‹ค)

Schedule์˜ ๋™์‹œ์„ฑ ๋ชจ๋ธ

  • immeidate() - ํ˜„์žฌ ์Šค๋ ˆ๋“œ์—์„œ ๊ตฌ๋… ์‹คํ–‰
  • single() - ๋‹จ์ผ์˜ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์Šค๋ ˆ๋“œ์—์„œ ๊ตฌ๋… ์‹คํ–‰. ๋ชจ๋“  ํ˜ธ์ถœ์ž์— ๋Œ€ํ•ด ๋™์ผํ•œ ์Šค๋ ˆ๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•จ
  • newSingle() - ๋งค ํ˜ธ์ถœ๋งˆ๋‹ค ์ „์šฉ ์Šค๋ ˆ๋“œ์—์„œ ๊ตฌ๋… ์‹คํ–‰
  • elastic() - ๋ฌดํ•œํ•˜๊ณ  ์‹ ์ถ•์„ฑ ์žˆ๋Š” ํ’€์—์„œ ๊ฐ€์ ธ์˜จ ์ž‘์—… ์Šค๋ ˆ๋“œ์—์„œ ๊ตฌ๋…์„ ์‹คํ–‰. ํ•„์š” ์‹œ ์ƒˆ๋กœ์šด ์ž‘์—… ์Šค๋ ˆ๋“œ๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ, ์œ ํœด ์Šค๋ ˆ๋“œ๋Š” ์ œ๊ฑฐ๋œ๋‹ค.
  • parallel() - ๊ณ ์ •๋œ ํฌ๊ธฐ์˜ ํ’€์—์„œ ๊ฐ€์ ธ์˜จ ์ž‘์—… ์Šค๋ ˆ๋“œ์—์„œ ๊ตฌ๋…์„ ์‹คํ–‰ํ•˜๋ฉฐ, CPU ์ฝ”์–ด์˜ ๊ฐœ์ˆ˜๊ฐ€ ํฌ๊ธฐ๊ฐ€ ๋œ๋‹ค.

๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์˜ ๋ฐ์ดํ„ฐ ๋ฒ„ํผ๋งํ•˜๊ธฐ

Flux๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋™์•ˆ ๋ฐ์ดํ„ฐ ์ŠคํŠธ๋ฆผ์„ ์ž‘์€ ๋ฉ์–ด๋ฆฌ๋กœ ๋ถ„ํ• ํ•˜๋ฉด ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ buffer() ์˜คํผ๋ ˆ์ด์…˜์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

image

@Test
  public void buffer() {
    Flux<String> fruitFlux = Flux.just(
        "apple", "orange", "banana", "kiwi", "strawberry");
    
    Flux<List<String>> bufferedFlux = fruitFlux.buffer(3);
    
    StepVerifier
        .create(bufferedFlux)
        .expectNext(Arrays.asList("apple", "orange", "banana"))
        .expectNext(Arrays.asList("kiwi", "strawberry"))
        .verifyComplete();
  }

์œ„ ์ฝ”๋“œ๋Š” Flux๋กœ๋ถ€ํ„ฐ ๋ฆฌ์•กํ‹ฐ๋ธŒ๊ฐ€ ์•„๋‹Œ List ์ปฌ๋ ‰์…˜์œผ๋กœ ๋ฒ„ํผ๋ง๋˜๋Š” ๊ฐ’์€ ๋น„์ƒ์‚ฐ์ ์ธ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ buffer()๋ฅผ flatMap()๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ List ์ปฌ๋ ‰์…˜์„ ๋ณ‘ํ–‰ ์ฒ˜๋ฆฌ ํ•  ์ˆ˜ ์žˆ๋‹ค.

@Test
  public void bufferAndFlatMap() throws Exception {
    Flux.just(
        "apple", "orange", "banana", "kiwi", "strawberry")
        .buffer(3)
        .flatMap(x -> 
          Flux.fromIterable(x)
            .map(y -> y.toUpperCase())
            .subscribeOn(Schedulers.parallel())   
            .log()
        ).subscribe();
  }

๋งŒ์•ฝ ์–ด๋–ค ์ด์œ ๋กœ๋“  Flux๊ฐ€ ๋ฐฉ์ถœํ•˜๋Š” ๋ชจ๋“  ํ•ญ๋ชฉ์„ List๋กœ ๋ชจ์„ ํ•„์š”๊ฐ€ ์žˆ๋‹ค๋ฉด ์ธ์ž๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š๊ณ  buffer()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋œ๋‹ค.

Flux<List<String>> bufferedFlux = fruitFlux.buffer();

10.3.4 ๋ฆฌ์•กํ‹ฐ๋ธŒ ํƒ€์ž…์— ๋กœ์ง ์˜คํผ๋ ˆ์ด์…˜ ์ˆ˜ํ–‰ํ•˜๊ธฐ

Mono๋‚˜ Flux๊ฐ€ ๋ฐœํ–‰ํ•œ ํ•ญ๋ชฉ์ด ์–ด๋–ค ์กฐ๊ฑด๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€๋งŒ ์•Œ์•„์•ผ ํ•  ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์ด๋•Œ๋Š” all() ์ด๋‚˜ any() ์˜คํผ๋ ˆ์ด์…˜์ด ๊ทธ๋Ÿฐ ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

image

@Test
public void all() {
  Flux<String> animalFlux = Flux.just(
      "aardvark", "elephant", "koala", "eagle", "kangaroo");
  
  Mono<Boolean> hasAMono = animalFlux.all(a -> a.contains("a"));
  StepVerifier.create(hasAMono)
    .expectNext(true)
    .verifyComplete();
  
  Mono<Boolean> hasKMono = animalFlux.all(a -> a.contains("k"));
  StepVerifier.create(hasKMono)
    .expectNext(false)
    .verifyComplete();
}

image

@Test
public void any() {
  Flux<String> animalFlux = Flux.just(
      "aardvark", "elephant", "koala", "eagle", "kangaroo");
  
  Mono<Boolean> hasAMono = animalFlux.any(a -> a.contains("a"));
  
  StepVerifier.create(hasAMono)
    .expectNext(true)
    .verifyComplete();
  
  Mono<Boolean> hasZMono = animalFlux.any(a -> a.contains("z"));
  StepVerifier.create(hasZMono)
    .expectNext(false)
    .verifyComplete();
}

์š”์•ฝ

  • ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ํ˜๋Ÿฌ๊ฐ€๋Š” ํŒŒ์ดํ”„๋ผ์ธ์„ ์ƒ์„ฑํ•œ๋‹ค.
  • ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์€ Publisher, Subscriber, Subscription, Transformer์˜ ๋„ค ๊ฐ€์ง€ ํƒ€์ž…์„ ์ •์˜ํ•œ๋‹ค.
  • ํ”„๋กœ์ ํŠธ ๋ฆฌ์•กํ„ฐ๋Š” ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ŠคํŠธ๋ฆผ์„ ๊ตฌํ˜„ํ•˜๋ฉฐ, ์ˆ˜๋งŽ์€ ์˜คํผ๋ ˆ์ด์…˜์„ ์ œ๊ณตํ•˜๋Š” Flux์™€ Mono์˜ ๋‘ ๊ฐ€์ง€ ํƒ€์ž…์œผ๋กœ ์ŠคํŠธ๋ฆผ์„ ์ •์˜ํ•œ๋‹ค.
  • ์Šคํ”„๋ง 5๋Š” ๋ฆฌ์•กํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ฆฌ์•กํ‹ฐ๋ธŒ ์ปจํŠธ๋กค๋Ÿฌ, ๋ฆฌํผ์ง€ํ„ฐ๋ฆฌ, REST ํด๋ผ์ด์–ธํŠธ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋‹ค๋ฅธ ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ง€์›ํ•œ๋‹ค.
โš ๏ธ **GitHub.com Fallback** โš ๏ธ