Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015

31,748 views

Published on

youtube : https://youtu.be/E_Bgv9upahI
비동기 이벤트 기반의 라이브러리로만 생각 했던 RxJava가 지금 이 시대 프로그래머에게 닥쳐 올 커다란 메시지라는 사실을 알게 된 지금. 현장에서 직접 느낀 RxJava의 본질인 Function Reactive Programming(FRP)에 대해 우리가 잘 아는 Java 이야기로 풀어 보고 ReactiveX(RxJava) 개발을 위한 서버 환경에 대한 이해와 SpringFramework, Netty에서의 RxJava를 어떻게 이용 하고 개발 했는지 공유 하고자 합니다.

Published in: Software
  • Be the first to comment

서버 개발자가 바라 본 Functional Reactive Programming with RxJava - SpringCamp2015

  1. 1. 서버 개발자가 바라 본 Functional Reactive Programming with RxJava 김대성 http://gmind7.github.io Java Software Developer
  2. 2. 2
  3. 3. 3
  4. 4. 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. 5. 5 eXchange programming paradigm
  6. 6. 6 FP RPFRP Functional Reactive Programming 이란?
  7. 7. 7
  8. 8. 8 COMPOSABLE FUNCTIONS REACTIVELY APPLIED d b ca
  9. 9. 9 RxJava getData(); Calling Thread Thread Pool Callback Thread Observable<Data>Public
  10. 10. 10 RxJava EVENT ITERABLE (PULL) OBSERVABLE (PUSH) Retrieve Data onNext(T) Discover Error onError(Exception) Complete onCompleted() PUSH 4 3 2 1 …..
  11. 11. 11 RxJava >> 4 3 2 1 ….. >> ObserverObservable PUSH
  12. 12. 12 RxJava Hello, World! Observable 데이터 발행 (PUSH) 하기 >> 4 3 2 1 ….. >> PUSH Observable<String> observable = Observable.create( new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("Hello, world!"); // 데이터 PUSH … next subscriber.onCompleted(); // 데이터 PUSH 이제 그만(완료) 할게.. } } );
  13. 13. 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. 14. 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. 15. 15 RxJava Hello, World! // java 7 Observable.just("Hello, world!").subscribe(new Action1<String>() { @Override public void call(String s) { System.out.println(s); } }); // java 8 Observable.just("Hello, world!").subscribe(System.out::println); // Outputs // Hello, world!
  16. 16. 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. 17. 17
  18. 18. 18
  19. 19. 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. 20. 20 1 2 3 4 5 6 … recommendService .requestRecommends(id) RxJava +
  21. 21. 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. 22. 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. 23. 23 1 2 3 4 5 6 … recommendService .requestRecommends(id) 1 2 3 4 5 unsubscribe .take(5) RxJava +
  24. 24. 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. 25. 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. 26. 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. 27. 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. 28. 28 ……………… .flatMap(recommend -> { // async 1 Observable<GoodsMetaInfo> goodsMetaInfo = goodsMetaInfo.findOne(recommend.id()) …….. RxJava +
  29. 29. 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. 30. 30 ……………… .flatMap(recommend -> { // async 1 Observable<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. 31. 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. 32. 32 RxJava ……………… .flatMap(recommend -> { // async 1 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; }); // async 2 Observable<GoodsRating> goodsRating = goodsRating.findOne(recommend.id()); ……. …. }) ……..
  33. 33. 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. 34. 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 3 return 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. 35. 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. 36. 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. 37. 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. 38. 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. 39. 39
  40. 40. 40
  41. 41. 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. 42. 42 ERROR
  43. 43. 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. 44. 44 RxJava + request Netty tcpwrite response tcpwrite public Channel… @Override public 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. 45. 45 RxJava + Netty public class ClientRequestHandler extends SimpleChannelInboundHandler<Object> { private final ConcurrentHashMap QUEUE = new ConcurrentHashMap<String, Subscriber<?>>; public ClientRequestHandler(){ }
  46. 46. 46 RxJava + Netty public 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")}); }; @Override protected 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. 47. 47 RxJava + Netty @Override public 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. 48. 48
  49. 49. 49
  50. 50. 50
  51. 51. 51
  52. 52. OOP CACHE RDBMS 1995 2015 HADOOP NOSQL FP, RX, FRP … 지금은 POLYGLOT 시대…
  53. 53. 53 http://www.manning.com/blackheath http://www.slideshare.net/InfoQ/functional-reactive-programming-in-the-netflix-api https://youtu.be/-P28LKWTzrI Towards Reactive Programming for Object-oriented Applications.pdf http://www.slideshare.net/misgod/functional-41887638 http://ent.hankyung.com/news/app/newsview.php?aid=2014112839734
  54. 54. 감사합니다

×