서버 개발자가 바라 본 functional reactive programming with rxjava - springcamp2015
TRANSCRIPT
서버 개발자가 바라 본Functional Reactive Programmingwith RxJava
김대성
http://gmind7.github.io
Java Software Developer
2
3
4
int a = 0;
int b = a*1;
int c = a*1;
int d = b*c;
.println(d) // 0
d
a
b c
d
b
a
Machine1
c
Machine2Actor Model
Functional Reactive Programming e.g
a = 2
.println(d) // ?
// b=2, c=2, d=4
5
eXchange programming paradigm
6
FP RPFRP
Functional Reactive Programming 이란?
7
8
COMPOSABLE FUNCTIONS
REACTIVELY APPLIED
d
b
ca
9
RxJava
getData();
Calling Thread
Thread Pool
Callback Thread
Observable<Data> Public
10
RxJava
EVENT ITERABLE (PULL) OBSERVABLE (PUSH)
Retrieve Data onNext(T)
Discover Error onError(Exception)
Complete onCompleted()
PUSH 4 3 2 1 …..
11
RxJava
>> 4 3 2 1 ….. >>
ObserverObservable
PUSH
12
RxJava Hello, World!
Observable
데이터 발행 (PUSH) 하기
>> 4 3 2 1 ….. >>PUSH
Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
@Overridepublic void call(Subscriber<? super String> subscriber) {
subscriber.onNext("Hello, world!"); // 데이터 PUSH … nextsubscriber.onCompleted(); // 데이터 PUSH 이제 그만(완료) 할게..
}}
);
13
RxJava
Observer
Hello, World!
PUSH 될 데이터 구독(소비) 계획 하기
>> 4 3 2 1 ….. >>
Subscriber<String> subscriber = new Subscriber<String>() {@Override // 구독 계획public void onNext(String s) { System.out.println("onNext:" + s); }@Override // 에러 계획public void onError(Throwable e) { System.out.println("onError:"+e.getMessage()); }@Override // 완료 계획public void onCompleted() { System.out.println("onComplated"); }
};
14
RxJava Hello, World!
// 2. PUSH 될 데이터 구독 계획Subscriber<String> subscriber = new Subscriber<String>() {……
// 3. 구독자가 가입 되면 데이터 발행 -> 구독 (Run)observable.subscribe(subscriber);
// 1. PUSH 데이터 생성 (Async)Observable<String> observable = Observable.create( ……
15
RxJava Hello, World!
// java 7Observable.just("Hello, world!").subscribe(new Action1<String>() {
@Overridepublic void call(String s) {
System.out.println(s);}
});
// java 8Observable.just("Hello, world!").subscribe(System.out::println);
// Outputs// Hello, world!
16
- Create
- Defer- Empty / Never ..- From- Interval- Just- Range- Repeat- Start- Timer…..
- And / Then / When
- CombineLatest- Join- Merge- StartWith- Switch- Map / FlatMap- Zip- Filter- IgnoreElemets- Last
…..
- Delay
- Do- Materialize- Dematerialize- ObserveOn- Serialize- Subscribe- SubscribeOn- TimeInterval- Timeout…..
17
18
19
@RequestMapping(value="/callable", method = RequestMethod.GET)public Callable<Object> callableShowAll() {
Callable<Object> callable = () -> accountService.findAll();return callable;
}
@RequestMapping(value="/rxjava", method = RequestMethod.GET)public DeferredResult<Object> rxJavaShowAll() {
DeferredResult<Object> deferredResult = new DeferredResult<>(5000L);Observable<List<Account>> resources = accountService.rxFindAll();resources.subscribe(response -> {
deferredResult.setResult(response);});return deferredResult;
}
RxJava +
20
1 2 3 4 5 6 …recommendService
.requestRecommends(id)
RxJava +
21
@RequestMapping(value="/{id}", method = RequestMethod.GET)public DeferredResult<Object> showYourStore(@PathVariable("id") Long id) {
DeferredResult<Object> deferredResult = new DeferredResult<>();Observable<Recommend> recommendRx = recommend.requestRecommends(id);…..deferredResult.setResult(response);
return deferredResult;
RxJava +
22
RxJava + public Observable<Recommend> requestRecommends(long accountId) {return Observable.from(RxNetty.createHttpGet("http://localhost:19080" + "/rxjava/recommend/" +
accountId).flatMap(response -> response.getContent().map(content ->
content.toString(Charset.defaultCharset()))).map(data -> new Gson().fromJson(new String(data), Recommend[].class))
.toBlocking().single());}
23
1 2 3 4 5 6 …recommendService
.requestRecommends(id)
1 2 3 4 5
unsubscribe
.take(5)
RxJava +
24
@RequestMapping(value="/{id}", method = RequestMethod.GET)public DeferredResult<Object> showYourStore(@PathVariable("id") Long id) {
DeferredResult<Object> deferredResult = new DeferredResult<>();Observable<Recommend> recommendRx = recommend.requestRecommends(id);recommendRx
.take(5)…..deferredResult.setResult(response);
return deferredResult;
RxJava +
25
1 2 6 …recommendService
.requestRecommends(id)
1 2.take(5)
.flatMap() 1 2
3
3
3
4
4
4
5
5
5
RxJava +
unsubscribe
26
@RequestMapping(value="/{id}", method = RequestMethod.GET)public DeferredResult<Object> showYourStore(@PathVariable("id") Long id) {
DeferredResult<Object> deferredResult = new DeferredResult<>();Observable<Recommend> recommendRx = recommend.requestRecommends(id);recommendRx
.take(3)
.flatMap(recommend -> {…….
}…..deferredResult.setResult(response);
return deferredResult;
RxJava +
27
1 2 3 4 5 6 …recommendService
.requestRecommends(id)
1 2 3 4 5.take(5)
.flatMap()
goodsMetaInfo()
1 2 3 4 5
1
RxJava +
unsubscribe
28
……………….flatMap(recommend -> {// async 1Observable<GoodsMetaInfo> goodsMetaInfo = goodsMetaInfo.findOne(recommend.id())
……..
RxJava +
29
1 2 3 4 5 6 …recommendService
.requestRecommends(id)
1 2 3 4 5.take(5)
.flatMap()
goodsMetaInfo()
.map()
1 2 3 4 5
1
1
RxJava +
unsubscribe
30
……………….flatMap(recommend -> {// async 1Observable<GoodsMetaInfo> goodsMetaInfo = goodsMetaInfo.findOne(recommend.id()).map(x -> { // 출시 1개월 이내 상품에는 [New] 타이틀 추가boolean isNewTitle = x.createDate.isAfter(LocalDateTime.now().minusMonths(1));if (isNewTitle) {x.setTitle("[New] " + x.getTitle());
}return x;
});…….….
})……..
RxJava +
31
1 2 3 4 5 6 …recommendService
.requestRecommends(id)
1 2 3 4 5.take(5)
.flatMap()
goodsMetaInfo()
goodsRating()
.map()
1 2 3 4 5
1
1
1
RxJava +
unsubscribe
32
RxJava ……………….flatMap(recommend -> {// async 1Observable<GoodsMetaInfo> goodsMetaInfo = goodsMetaInfo.findOne(recommend.id()).map(x -> {
boolean isNewTitle = x.createDate.isAfter(LocalDateTime.now().minusMonths(1));if (isNewTitle) {
x.setTitle("[New] " + x.getTitle());}return x;
});// async 2Observable<GoodsRating> goodsRating = goodsRating.findOne(recommend.id());…….….
})……..
33
1 2 3 4 5 6 …recommendService
.requestRecommends(id)
1 2 3 4 5.take(5)
.flatMap()
goodsMetaInfo()
goodsRating()
.map()
1 2 3 4 5
1
1
.zip()
1
1
RxJava
unsubscribe
34
……………….flatMap(recommend -> {Observable<GoodsMetaInfo> goodsMetaInfo = goodsMetaInfo.findOne(recommend.id()).map(x -> {
boolean isNewTitle = x.createDate.isAfter(LocalDateTime.now().minusMonths(1));if (isNewTitle) {
x.setTitle("[New] " + x.getTitle());}return x;
});Observable<GoodsRating> goodsRating = goodsRating.findOne(recommend.id());// async 3return Observable.zip(goodsMetaInfo, goodsRating, (x, y) -> {Map<String, Object> map = Maps.newHashMap();map.put("recommend", recommend);map.put("goods", x);map.put("rating", y);return map;
});})……..
RxJava +
35
1 2 3 4 5 6 …recommendService
.requestRecommends(id)
1 2 3 4 5
unsubscribe
.take(5)
.flatMap()
goodsMetaInfo()
goodsRating()
.map()
1 2 3 4 5
1
1
.zip()
1
1
.toList() 1 2 3 4 5
RxJava +
36
@RequestMapping(value="/{id}", method = RequestMethod.GET)public DeferredResult<Object> showYourStore(@PathVariable("id") Long id) {
DeferredResult<Object> deferredResult = new DeferredResult<>();Observable<Recommend> recommendRx = recommend.requestRecommends(id);recommendRx
.take(3)
.flatMap(recommend -> { ……
}).toList()…..
return deferredResult;
RxJava +
37
@RequestMapping(value="/{id}", method = RequestMethod.GET)public DeferredResult<Object> showYourStore(@PathVariable("id") Long id) {DeferredResult<Object> deferredResult = new DeferredResult<>();Observable<Recommend> recommendRx = recommend.requestRecommends(id);recommendRx.take(3).flatMap(recommend -> {
……..……..})
.toList()
.timeout(5L, TimeUnit.SECONDS)
.subscribe(response -> {deferredResult.setResult(response);
}, error -> {deferredResult.setErrorResult(error);
}, () -> {});
return deferredResult;
RxJava +
38
@RequestMapping(value="/{id}", method = RequestMethod.GET)public DeferredResult<Object> showYourStore(@PathVariable("id") Long id) {DeferredResult<Object> deferredResult = new DeferredResult<>();Observable<Recommend> recommendRx = recommend.requestRecommends(id);recommendRx.take(3).flatMap(recommend -> {
……..……..})
.toList()
.timeout(5L, TimeUnit.SECONDS)
.subscribe(response -> {
deferredResult.setResult(response);}, error -> {deferredResult.setErrorResult(error);
}, () -> {});
return deferredResult;
RxJava +
39
40
41
……………….flatMap(recommend -> {Observable<GoodsMetaInfo> goodsMetaInfo = goodsMetaInfo.findOne(recommend.id())….subscribeOn(Schedulers.computation()); Observable<GoodsRating> goodsRating = goodsRating.findOne(recommend.id())….subscribeOn(Schedulers.computation());return Observable.zip(goodsMetaInfo, goodsRating, (x, y) -> {…return map;
}).subscribeOn(Schedulers.computation());})……..
RxJava +
42
ERROR
43
@RequestMapping(value="/{id}", method = RequestMethod.GET)public DeferredResult<Object> showYourStore(@PathVariable("id") Long id) {DeferredResult<Object> deferredResult = new DeferredResult<>();Observable<Recommend> recommendRx = recommend.requestRecommends(id);recommendRx.take(3).flatMap(recommend -> {
Observable<GoodsMetaInfo> goodsMetaInfo = goodsMetaInfo….…Observable<GoodsRating> goodsRating = goodsRating……})
.toList()
.timeout(5L, TimeUnit.SECONDS)
.subscribe(response -> {deferredResult.setResult(response);
}, error -> {deferredResult.setErrorResult(error);
}, () -> {});
return deferredResult;
RxJava +
44
RxJava +
request
Netty
tcpwrite
response
tcpwrite
public Channel…
@Overridepublic void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {Account message = new Account(1);Observable<Object> observable = clientReqHandler.request(ctx.channel(), message);observable.subscribe(response -> {ctx.channel().writeAndFlush(response);
});}
?tcpread
public void …
45
RxJava + Nettypublic class ClientRequestHandler extends SimpleChannelInboundHandler<Object> {private final ConcurrentHashMap QUEUE = new ConcurrentHashMap<String, Subscriber<?>>;
public ClientRequestHandler(){}
46
RxJava + Nettypublic Observable<Object> request(final Channel channel, final Object message) {return Observable.<Object>create(suscriber -> {
this.QUEUE.put("requestId", suscriber);channel.writeAndFlush(message);
}).timeout(5L, TimeUnit.SECONDS).finallyDo(() -> queue.remove("requestId")});
};
@Overrideprotected void channelRead0(ChannelHandlerContext channelHandlerContext, Object object) throws Exception {Subscriber subscriber = (Subscriber)this.QUEUE.remove("requestId");if(subscriber==null) return;subscriber.onNext(object);subscriber.onCompleted();
}
47
RxJava + Netty
@Overridepublic void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {Account message = new Account(1);Observable<Object> observable = clientReqHandler.request(ctx.channel(), message);observable.subscribe(response -> {ctx.channel().writeAndFlush(response);
});}
request1
tcpwrite
response1
tcpwrite
public void …tcpread
public void …
48
49
50
51
OOP
CACHE
RDBMS
1995 2015
HADOOP
NOSQL
FP, RX, FRP …
지금은 POLYGLOT 시대…
53
http://www.manning.com/blackheathhttp://www.slideshare.net/InfoQ/functional-reactive-programming-in-the-netflix-apihttps://youtu.be/-P28LKWTzrITowards Reactive Programming for Object-oriented Applications.pdfhttp://www.slideshare.net/misgod/functional-41887638http://ent.hankyung.com/news/app/newsview.php?aid=2014112839734
감사합니다