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.

Reactive Web - Servlet & Async, Non-blocking I/O

2,485 views

Published on

자바 서블릿(Java Servlet) 기술을 기반으로
리액티브 웹(REACTIVE WEB) 구현 과정을 공유!

1부, Servlet & Async, Non-blocking I/O
2부, Reactive Programing (작성 중)
3부, Spring Reactive Web (작성 중)

Published in: Software
  • Controversial method reveals inner psychology of techniques you can use to get your Ex back! See it now! ➤➤ http://t.cn/R50e2MX
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Visit this site: tinyurl.com/sexinarea and find sex in your area for one night)) You can find me on this site too)
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Sex in your area for one night is there tinyurl.com/hotsexinarea Copy and paste link in your browser to visit a site)
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Girls for sex are waiting for you https://bit.ly/2TQ8UAY
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Meetings for sex in your area are there: https://bit.ly/2TQ8UAY
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

Reactive Web - Servlet & Async, Non-blocking I/O

  1. 1. Ý 
  2. 2. Servlet 2.2 JSP 1.1 Servlet 2.3 JSP 1.2 JSTL 1.0 Servlet 2.4 JSP 2.0 JSTL 1.1 Servlet 2.5 JSP 2.1 EL 2.1 JSTL 1.2 Servlet 3.0 JSP 2.2 EL 2.2 JSTL 1.2 Servlet 3.1 JSP 2.3 EL 3.0 JSTL 1.2
  3. 3. Ý 

  4. 4. Ý GET /hello?name=arwan HTTP/1.1 <html> … </html> Tomcat Undertow Jetty HttpServletRequest
 HttpServletResponse @WebServlet(urlPatterns = {"/hello"}) class HelloServlet extends HttpServlet { … }
  5. 5. Ý Ý Ý Ý
  6. 6. Ý Ý Ý Ý{ “content”: “…” }
  7. 7. Ý
  8. 8. var es = new EventSource(‘/notification/stream'); es.onmessage = function (event) { // }; es.addEventListener(‘feed-notify', function(event) { // ‘feed-notify' console.log(event.data); }, false); es.onerror = function (event) { // };
  9. 9. @WebServlet("/notification/stream")
 public class NotificationStreamServlet extends HttpServlet {
 final static Log log = LogFactory.getLog(NotificationStreamServlet.class); 
 @Override
 protected void service(HttpServletRequest request, HttpServletResponse response) throws Exception { log.info("in notification/stream");
 
 response.setCharacterEncoding("utf-8");
 response.setContentType("text/event-stream");
 
 try {
 NotificationStream notificationStream = new NotificationStream(obtainUsername(request));
 Iterator<Notification> notifies = notificationStream.feedNotifies();
 
 while (notifies.hasNext()) {
 Notification notification = notifies.next();
 
 ServletOutputStream outputStream = response.getOutputStream();
 outputStream.write(("event: " + notification.getEvent() + "n").getBytes());
 outputStream.write(("data: " + notification.getData() + "nn").getBytes());
 outputStream.flush();
 }
 } catch (Exception error) {
 log.error("error notification/stream : " + error.getMessage());
 }
 
 log.info("out notification/stream”); }
 
 String obtainUsername(HttpServletRequest request) {
 return request.getParameter("username");
 }
 }
  10. 10. class FeedService {
 
 final String FEED_NOTIFY_URL = "http://localhost:9000/user/%s/feed";
 final ObjectMapper MAPPER = new ObjectMapper();
 
 FeedNotify getFeedNotify(String username) {
 try {
 URL url = new URL(String.format(FEED_NOTIFY_URL, username));
 
 HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
 urlConnection.setRequestMethod("GET");
 urlConnection.setRequestProperty("Accept", "application/json");
 urlConnection.setConnectTimeout(3000);
 urlConnection.setReadTimeout(3000);
 
 return MAPPER.readValue(urlConnection.getInputStream(), FeedNotify.class);
 } catch (IOException error) {
 throw new ServiceOperationException(error);
 }
 }
 
 } // FeedService , 
 FeedService feedService = new FeedService();
 
 String username = "guest";
 Iterator<Notification> feedNotifies = Stream.generate(() -> feedService.getFeedNotify(username))
 .map(Notification::of)
 .iterator();
 
 
 while (feedNotifies.hasNext()) {
 Notification next = feedNotifies.next();
 
 System.out.println(next);
 }
  11. 11. Ý
  12. 12. @WebServlet(urlPatterns = "/async", asyncSupported = true)
 public class SimpleAsyncServlet extends HttpServlet {
 protected void service(HttpServletRequest request, HttpServletResponse response) throws Exception { 
 // 
 AsyncContext asyncContext = request.startAsync(request, response);
 // 
 asyncContext.setTimeout(60 * 1000); 
 // 
 asyncContext.addListener(new AsyncListener() {
 // public void onComplete(AsyncEvent event) throws IOException { … } // AsyncContext.setTimeout() 
 public void onTimeout(AsyncEvent event) throws IOException { … }
 // public void onError(AsyncEvent event) throws IOException { … } // 
 public void onStartAsync(AsyncEvent event) throws IOException { … }
 });
 // 
 asyncContext.start(new Runnable() {
 public void run() {
 // 
 asyncContext.complete(); // 
 }
 });
 }
 }
  13. 13. @WebServlet(urlPatterns = "/notification/stream/async", asyncSupported = true)
 public class AsyncNotificationStreamServlet extends HttpServlet {
 
 @Override
 protected void service(HttpServletRequest request, HttpServletResponse response) throws Exception {
 log.info("in notification/stream/async");
 
 response.setCharacterEncoding("utf-8");
 response.setContentType("text/event-stream");
 
 AsyncContext asyncContext = request.startAsync();
 asyncContext.setTimeout(30000);
 asyncContext.addListener(new AsyncListener() {
 public void onComplete(AsyncEvent event) throws IOException { … }
 public void onTimeout(AsyncEvent event) throws IOException { … }
 public void onError(AsyncEvent event) throws IOException { … }
 public void onStartAsync(AsyncEvent event) throws IOException { … }
 });
 asyncContext.start(() -> {
 try {
 NotificationStream notificationStream = new NotificationStream(obtainUsername(request));
 Iterator<Notification> notifies = notificationStream.feedNotifies();
 
 while (notifies.hasNext() && !asyncDone.get()) {
 Notification notification = notifies.next();
 
 ServletOutputStream outputStream = asyncContext.getResponse().getOutputStream();
 outputStream.write(("event: " + notification.getEvent() + "n").getBytes());
 outputStream.write(("data: " + notification.getData() + "nn").getBytes());
 outputStream.flush();
 }
 } catch (Exception error) {
 log.error("error notification/stream/async - " + error.getMessage());
 } finally {
 asyncContext.complete();
 }
 });
 
 log.info("out notification/stream/async");
 } }
  14. 14. Ý Ý Ý Ý
  15. 15. class NotifyApi {
 
 static Log LOG = LogFactory.getLog(NotifyApi.class);
 
 final String FEED_NOTIFY_URL = "http://localhost:9000/user/%s/feed";
 final String FRIEND_NOTIFY_URL = "http://localhost:9000/user/%s/friend-recommendation";
 
 final ObjectMapper MAPPER = new ObjectMapper();
 
 FeedNotify getFeedNotify(String username) {
 LOG.info("FeedNotify .");
 
 try {
 URL url = new URL(String.format(FEED_NOTIFY_URL, username));
 HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
 FeedNotify feedNotify = MAPPER.readValue(urlConnection.getInputStream(), FeedNotify.class);
 
 LOG.info("FeedNotify .");
 
 return feedNotify;
 } catch (IOException error) {
 throw new ServiceOperationException(error);
 }
 }
 
 FriendRecommendationNotify getFriendRecommendationNotify(String username) {
 LOG.info("FriendRecommendationNotify .");
 try {
 URL url = new URL(String.format(FRIEND_NOTIFY_URL, username));
 // 
 
 LOG.info("FriendRecommendationNotify .");
 
 return notify;
 } catch (IOException error) {
 throw new ServiceOperationException(error);
 }
 }
 }
  16. 16. public class SynchronousCallExample {
 
 public static void main(String[] args) {
 
 
 NotifyApi notifyApi = new NotifyApi();
 String username = "guest";
 
 
 FeedNotify feedNotify = notifyApi.getFeedNotify(username);
 
 // feedNotify 
 
 
 FriendRecommendationNotify friendNotify = notifyApi.getFriendRecommendationNotify(username);
 
 // friendNotify 
 
 }
 
 }
  17. 17. FeedNotify getFeedNotify(username) HTTP / FriendRecommendationNotify getFriendRecommendationNotify(username) HTTP /
  18. 18. public class AsynchronousCallByThreadExample {
 
 static Log LOG = LogFactory.getLog(AsynchronousCallByThreadExample.class);
 
 public static void main(String[] args) throws Exception {
 
 NotifyApi notifyApi = new NotifyApi();
 String username = "guest";
 
 Thread feedThread = new Thread(new Runnable() {
 
 @Override
 public void run() {
 
 FeedNotify feedNotify = notifyApi.getFeedNotify(username);
 LOG.info(feedNotify);
 
 }
 
 });
 feedThread.start();
 
 
 Thread friendThread = new Thread(() -> {
 
 FriendRecommendationNotify friendNotify = notifyApi.getFriendRecommendationNotify(username);
 LOG.info(friendNotify);
 
 });
 friendThread.start();
 
 }
 
 }
  19. 19. <<Interface>> Executor <<Interface>> ExecutorService <<Interface>> ScheduledExecutorService ForkJoinPool AbstractExecutorService ThreadPoolExecutor ScheduledThreadPoolExecutor ExecutorService executorService = Executors.newFixedThreadPool(4);
  20. 20. public class AsynchronousCallByExecutorExample {
 
 static Log LOG = LogFactory.getLog(AsynchronousCallByExecutorExample.class);
 
 public static void main(String[] args) throws Exception {
 
 NotifyApi notifyApi = new NotifyApi();
 String username = "guest";
 
 
 Executor executor = Executors.newFixedThreadPool(4);
 
 
 executor.execute(new Runnable() { 
 @Override
 public void run() {
 FeedNotify feedNotify = notifyApi.getFeedNotify(username);
 LOG.info(feedNotify);
 } 
 });
 
 executor.execute(() -> { 
 FriendRecommendationNotify friendNotify = notifyApi.getFriendRecommendationNotify(username);
 LOG.info(friendNotify); 
 });
 
 }
 
 }
  21. 21. ExecutorService executorService = Executors.newCachedThreadPool();
 
 Future<String> future = executorService.submit(new Callable<String>() { 
 @Override
 public String call() throws Exception {
 
 // 
 
 return "asynchronous call";
 } 
 });
 
 String result = future.get(1, TimeUnit.SECONDS);
  22. 22. class NotifyApi {
 
 static Log LOG = LogFactory.getLog(NotifyApi.class);
 
 final String FEED_NOTIFY_URL = "http://localhost:9000/user/%s/feed";
 final String FRIEND_NOTIFY_URL = "http://localhost:9000/user/%s/friend-recommendation";
 
 final ExecutorService executorService = Executors.newCachedThreadPool();
 final ObjectMapper objectMapper = new ObjectMapper();
 
 FeedNotify getFeedNotify(String username) { … }
 
 Future<FeedNotify> getFeedNotifyForFuture(String username) { 
 return executorService.submit(new Callable<FeedNotify>() { 
 @Override
 public FeedNotify call() throws Exception {
 return getFeedNotify(username);
 } 
 });
 }
 
 FriendRecommendationNotify getFriendRecommendationNotify(String username) { … }
 
 Future<FriendRecommendationNotify> getFriendRecommendationNotifyForFuture(String username) {
 return executorService.submit(() -> getFriendRecommendationNotify(username));
 }
 
 }
  23. 23. NotifyApi notifyApi = new NotifyApi();
 String username = "guest";
 
 
 Future<FeedNotify> feedFuture = notifyApi.getFeedNotifyForFuture(username);
 Future<FriendRecommendationNotify> friendFuture = notifyApi.getFriendRecommendationNotifyForFuture(username);
 
 for (;;) {
 if (feedFuture.isDone()) {
 FeedNotify feedNotify = feedFuture.get();
 
 // feedNotify 
 
 break;
 }
 
 // 
 // feedFuture.cancel(true); 
 LOG.info("FeedNotify .");
 Thread.sleep(100);
 }
 
 
 FriendRecommendationNotify friendNotify = friendFuture.get(1, TimeUnit.SECONDS);
 
 // friendNotify
  24. 24. getFeedNotify(username) HTTP / feedFuture HTTP / friendFuture getFriendRecommendationNotify(username) feedFuture.isDone() or cancel() feedFuture.get() friendFuture.get()
  25. 25. NotifyApi notifyApi = new NotifyApi();
 String username = "elton";
 
 
 Future<User> userFuture = notifyApi.getUserForFuture(username);
 for (;;) {
 if (userFuture.isDone()) {
 User user = userFuture.get();
 
 FeedNotify feedNotify = notifyApi.getFeedNotifyForFuture(user) .get(1, TimeUnit.SECONDS);
 
 // 
 
 break;
 }
 
 LOG.info("User .");
 Thread.sleep(100);
 }
  26. 26. NotifyApi notifyApi = new NotifyApi();
 String username = "guest"; notifyApi.getFeedNotify(username, new CompletionHandler<FeedNotify>() {
 
 @Override
 public void onSuccess(FeedNotify result) {
 // 
 }
 
 @Override
 public void onFailure(Throwable ex) {
 // 
 } 
 });
  27. 27. class NotifyApi {
 // 
 interface CompletionHandler<R> extends SuccessCallback<R>, FailureCallback { } // 
 interface SuccessCallback<R> { 
 void onSuccess(R result); 
 } // 
 interface FailureCallback { 
 void onFailure(Throwable ex); 
 } 
 }
  28. 28. class NotifyApi {
 
 static Log LOG = LogFactory.getLog(NotifyApi.class);
 
 final String FEED_NOTIFY_URL = "http://localhost:9000/user/%s/feed";
 final String FRIEND_NOTIFY_URL = "http://localhost:9000/user/%s/friend-recommendation";
 
 final ExecutorService executorService = Executors.newCachedThreadPool();
 final ObjectMapper objectMapper = new ObjectMapper();
 
 FeedNotify getFeedNotify(String username) { … }
 
 void getFeedNotify(String username, CompletionHandler<FeedNotify> completionHandler) {
 executorService.execute(new Runnable() { 
 @Override
 public void run() {
 try {
 completionHandler.onSuccess(getFeedNotify(username));
 } catch (Exception error) {
 completionHandler.onFailure(error);
 }
 } 
 });
 }
 
 FriendRecommendationNotify getFriendRecommendationNotify(String username) { … }
 
 void getFriendRecommendationNotify(String username, CompletionHandler<FriendRecommendationNotify> handler) { … }
 
 }
  29. 29. NotifyApi notifyApi = new NotifyApi();
 String username = "guest";
 
 
 notifyApi.getFeedNotify(username, new CompletionHandler<FeedNotify>() {
 
 @Override
 public void onSuccess(FeedNotify result) {
 // 
 }
 
 @Override
 public void onFailure(Throwable ex) {
 // 
 } 
 });
 
 
 notifyApi.getFriendRecommendationNotify(username, new CompletionHandler<FriendRecommendationNotify>() { 
 @Override
 public void onSuccess(FriendRecommendationNotify result) {
 } 
 @Override
 public void onFailure(Throwable ex) {
 } 
 }); 

  30. 30. execute callback getFeedNotify(username) HTTP / execute callback getFriendRecommendationNotify(username) HTTP /
  31. 31. NotifyApi notifyApi = new NotifyApi();
 String username = "elton";
 
 
 notifyApi.getUser(username, new NotifyApi.CompletionHandler<User>() {
 
 @Override
 public void onSuccess(User user) {
 
 notifyApi.getFeedNotify(user, new NotifyApi.CompletionHandler<FeedNotify>() {
 
 @Override
 public void onSuccess(FeedNotify feedNotify) {
 // 
 }
 
 @Override
 public void onFailure(Throwable error) {
 // 
 }
 
 });
 
 }
 
 @Override
 public void onFailure(Throwable error) {
 // 
 }
 
 });
  32. 32. CompletableFuture.supplyAsync(() -> {
 
 // 
 
 return "async task";
 }).thenApply(result -> {
 
 // 
 
 return result.length();
 }).exceptionally(error -> {
 
 // 
 
 return Integer.MIN_VALUE;
 }).thenAccept(length -> {
 
 // 
 
 LOG.info("Length : " + length);
 });
  33. 33. class NotifyApi {
 
 static Log LOG = LogFactory.getLog(NotifyApi.class);
 
 final String FEED_NOTIFY_URL = "http://localhost:9000/user/%s/feed";
 final String FRIEND_NOTIFY_URL = "http://localhost:9000/user/%s/friend-recommendation";
 
 final ExecutorService executorService = Executors.newCachedThreadPool();
 final ObjectMapper objectMapper = new ObjectMapper();
 
 FeedNotify getFeedNotify(String username) { … }
 
 CompletableFuture<FeedNotify> getFeedNotifyForCF(String username) { return CompletableFuture.supplyAsync(new Supplier<FeedNotify>() { 
 @Override
 public FeedNotify get() {
 return getFeedNotify(username);
 } 
 }, executorService);
 }
 
 FriendRecommendationNotify getFriendRecommendationNotify(String username) { … }
 
 CompletableFuture<FriendRecommendationNotify> getFriendRecommendationNotifyForCF(String username) {
 return CompletableFuture.supplyAsync(() -> getFriendRecommendationNotify(username), executorService);
 }
 
 }
  34. 34. NotifyApi notifyApi = new NotifyApi();
 String username = "guest";
 
 
 notifyApi.getFeedNotifyForCF(username).thenAccept(feedNotify -> {
 // feedNotify 
 });
 
 notifyApi.getFriendRecommendationNotifyForCF(username).thenAccept(friendNotify -> {
 // friendNotify 
 });
 
 
 // 2 
 notifyApi.getUserForCF(username)
 .thenCompose(notifyApi::getFeedNotifyForCF)
 .thenAccept(notifications -> {
 // 
 });
  35. 35.
  36. 36. class NotificationStreamObservable {
 
 ExecutorService executorService = Executors.newFixedThreadPool(1);
 Future<?> future = new FutureTask<>(() -> {}, null);
 
 NotifyApi notifyApi = new NotifyApi();
 
 String username;
 List<NotificationStreamObserver> observers = new CopyOnWriteArrayList<>();
 
 NotificationStreamObservable(String username) {
 this.username = username;
 }
 
 void register(NotificationStreamObserver observer) {
 observers.add(observer);
 }
 
 void unregister(NotificationStreamObserver observer) {
 observers.remove(observer);
 }
 
 void subscribe() {
 future = executorService.submit(() -> {
 boolean running = true;
 while (running) {
 Notification feedNotify = Notification.of(notifyApi.getFeedNotify(username));
 observers.forEach(observer -> observer.onNotification(feedNotify)); // 
 }
 });
 }
 
 void unsubscribe() {
 future.cancel(true);
 observers.clear();
 }
 }
  37. 37. interface NotificationStreamObserver {
 
 void onNotification(Notification notification);
 
 } 
 String username = "guest";
 
 NotificationStreamObservable observable = new NotificationStreamObservable(username);
 observable.register(notification -> {
 
 // 
 
 });
 observable.subscribe();
 
 
 // , 
 // observable.unsubscribe();
  38. 38. @WebServlet(urlPatterns = "/notification/stream/async", asyncSupported = true)
 public class AsyncNotificationStreamServlet extends HttpServlet {
 @Override
 protected void service(HttpServletRequest request, HttpServletResponse response) throws Exception {
 log.info("in notification/stream/async");
 
 response.setCharacterEncoding("utf-8");
 response.setContentType("text/event-stream");
 
 AtomicBoolean asyncDone = new AtomicBoolean(false);
 
 AsyncContext asyncContext = request.startAsync();
 asyncContext.setTimeout((new Random().nextInt(5) + 5) * 1000);
 asyncContext.addListener(new AsyncListener() {
 
 @Override
 public void onComplete(AsyncEvent event) throws IOException { }
 
 @Override
 public void onTimeout(AsyncEvent event) throws IOException { }
 
 @Override
 public void onError(AsyncEvent event) throws IOException { }
 
 @Override
 public void onStartAsync(AsyncEvent event) throws IOException { }
 
 }); 
 asyncContext.start(() -> {
 // 
 });
 
 log.info("out notification/stream/async");
 } }
  39. 39. @WebServlet(urlPatterns = "/notification/stream/async", asyncSupported = true)
 public class AsyncNotificationStreamServlet extends HttpServlet {
 @Override
 protected void service(HttpServletRequest request, HttpServletResponse response) throws Exception {
 log.info("in notification/stream/async");
 
 response.setCharacterEncoding("utf-8");
 response.setContentType("text/event-stream");
 
 AtomicBoolean asyncDone = new AtomicBoolean(false);
 
 AsyncContext asyncContext = request.startAsync();
 asyncContext.setTimeout((new Random().nextInt(5) + 5) * 1000);
 asyncContext.addListener(new AsyncListener() {
 
 @Override
 public void onComplete(AsyncEvent event) throws IOException { }
 
 @Override
 public void onTimeout(AsyncEvent event) throws IOException { }
 
 @Override
 public void onError(AsyncEvent event) throws IOException { }
 
 @Override
 public void onStartAsync(AsyncEvent event) throws IOException { }
 
 }); 
 asyncContext.start(() -> {
 // 
 });
 
 log.info("out notification/stream/async");
 } }
  40. 40. Ý Ý
  41. 41. public class NotificationStreamObservable extends Observable {
 
 final static ExecutorService executorService = Executors.newCachedThreadPool();
 
 Iterator<Notification> feedNotifies;
 Future<?> feedFuture;
 
 public NotificationStreamObservable(NotificationStream stream) {
 this.feedNotifies = Objects.requireNonNull(stream.feedNotifies());
 }
 
 public void subscribe() {
 feedFuture = executorService.submit(() -> {
 boolean running = true;
 while (running) {
 if (countObservers() > 0) {
 try {
 Notification notification = feedNotifies.next();
 
 setChanged();
 notifyObservers(notification);
 } catch (Exception error) {
 running = false;
 
 setChanged();
 notifyObservers(error);
 }
 }
 if (Thread.interrupted()) {
 running = false;
 }
 Thread.yield();
 }
 });
 }
 
 public void unsubscribe() {
 feedFuture.cancel(true);
 deleteObservers();
 } }
  42. 42. class NotificationStreamObserver implements Observer, AsyncListener {
 
 final AsyncContext asyncContext;
 
 public NotificationStreamObserver(AsyncContext asyncContext) {
 this.asyncContext = Objects.requireNonNull(asyncContext);
 }
 
 @Override
 public void update(Observable observable, Object event) {
 if (event instanceof Notification) {
 handler((Notification) event);
 }
 
 // 
 if (event instanceof Throwable) {
 handlerError(observable, (Throwable) event);
 }
 }
 
 @Override
 public void onComplete(AsyncEvent event) throws IOException {
 log.info("complete notification/stream/async-observer");
 }
 
 @Override
 public void onTimeout(AsyncEvent event) throws IOException {
 handlerError(new TimeoutException("timeout"));
 }
 
 @Override
 public void onError(AsyncEvent event) throws IOException {
 handlerError(event.getThrowable());
 }
 
 @Override
 public void onStartAsync(AsyncEvent event) throws IOException { }
 // handle, handleError }
  43. 43. @WebServlet(urlPatterns = "/notification/stream/observer", asyncSupported = true)
 public class ObserverNotificationStreamServlet extends HttpServlet {
 
 @Override
 protected void service(HttpServletRequest request, HttpServletResponse response) throws Exception {
 log.info("in notification/stream/observer");
 
 response.setCharacterEncoding("utf-8");
 response.setContentType("text/event-stream");
 
 
 AsyncContext asyncContext = request.startAsync(request, response);
 asyncContext.setTimeout((new Random().nextInt(5) + 5) * 1000);
 
 NotificationStream notificationStream = new NotificationStream(obtainUsername(request));
 NotificationStreamObservable streamObservable = new NotificationStreamObservable(notificationStream);
 
 NotificationStreamObserver streamObserver = new NotificationStreamObserver(asyncContext);
 streamObservable.addObserver(streamObserver);
 asyncContext.addListener(streamObserver);
 
 streamObservable.subscribe();
 
 log.info("out notification/stream/observer");
 }
 
 String obtainUsername(HttpServletRequest request) {
 String username = request.getParameter("username");
 if (StringUtils.hasText(username)) {
 return username;
 }
 
 return "anonymous";
 } 
 }
  44. 44. Ý Ý Ý Ý
  45. 45. public class NotificationStreamObservable extends Observable {
 
 final static ExecutorService executorService = Executors.newCachedThreadPool();
 
 Iterator<Notification> feedNotifies;
 Future<?> feedFuture;
 
 public NotificationStreamObservable(NotificationStream stream) {
 this.feedNotifies = requireNonNull(stream).feedNotifies();
 }
 
 public void subscribe() {
 feedFuture = executorService.submit(() -> {
 boolean running = true;
 while (running) {
 if (countObservers() > 0) {
 try {
 Notification notification = feedNotifies.next(); 
 setChanged();
 notifyObservers(notification);
 } catch (Exception error) {
 running = false;
 
 setChanged();
 notifyObservers(error);
 }
 } // 
 }
 });
 }
 // }
  46. 46. public class NotificationStreamObservable extends Observable {
 
 final static ExecutorService executorService = Executors.newCachedThreadPool();
 
 Iterator<Notification> feedNotifies;
 Future<?> feedFuture; Iterator<Notification> friendNotifies;
 Future<?> friendFuture;
 
 public NotificationStreamObservable(NotificationStream stream) {
 this.feedNotifies = requireNonNull(stream).feedNotifies();
 this.friendNotifies = requireNonNull(stream).friendRecommendationNotifies();
 }
 
 public void subscribe() {
 feedFuture = executorService.submit(() -> {
 boolean running = true;
 while (running) {
 if (countObservers() > 0) {
 try {
 Notification feedNotify = feedNotifies.next();
 setChanged();
 notifyObservers(feedNotify); Notification friendNotify = friendNotifies.next();
 setChanged();
 notifyObservers(friendNotify);
 } catch (Exception error) {
 running = false;
 
 setChanged();
 notifyObservers(error);
 }
 } // 
 }
 });
 }
 // }
  47. 47. feedNotifies.next() friendNotifies.next() feedNotify friendNotify
  48. 48. class NotificationPublisher implements Runnable {
 
 final Iterator<Notification> notifies;
 final AtomicBoolean running = new AtomicBoolean(true);
 
 NotificationPublisher(Iterator<Notification> notifies) {
 this.notifies = notifies;
 }
 
 @Override
 public void run() {
 while (running.get()) {
 if (countObservers() > 0) {
 try {
 Notification notification = notifies.next();
 
 setChanged();
 notifyObservers(notification);
 } catch (Exception error) {
 cancel();
 
 setChanged();
 notifyObservers(error);
 }
 }
 
 if (Thread.interrupted()) {
 cancel();
 }
 
 Thread.yield();
 }
 }
 
 void cancel() {
 running.set(false);
 }
 
 }
  49. 49. class MultipleNotificationStreamObservable extends Observable {
 
 final static ExecutorService executor = Executors.newCachedThreadPool();
 
 NotificationPublisher feedPublisher;
 NotificationPublisher friendPublisher;
 
 public MultipleNotificationStreamObservable(NotificationStream stream) {
 this.feedPublisher = new NotificationPublisher(requireNonNull(stream).feedNotifies());
 this.friendPublisher = new NotificationPublisher(requireNonNull(stream).friendRecommendationNotifies());
 }
 
 public void subscribe() {
 executor.execute(feedPublisher);
 executor.execute(friendPublisher);
 }
 
 public void unsubscribe() {
 feedPublisher.cancel();
 friendPublisher.cancel();
 
 deleteObservers();
 }
 
 }
  50. 50. class MultipleNotificationStreamObserver implements Observer, AsyncListener {
 
 @Override
 public void update(Observable observable, Object event) { 
 synchronized (this) {
 if (event instanceof Notification) {
 handler((Notification) event);
 }
 
 // 
 if (event instanceof Throwable) {
 handlerError((Throwable) event);
 }
 } 
 }
 
 // }
  51. 51. class MultipleNotificationStreamObserver implements Observer, AsyncListener {
 
 ReentrantLock reentrantLock = new ReentrantLock();
 
 @Override
 public void update(Observable observable, Object event) {
 
 reentrantLock.lock();
 
 if (event instanceof Notification) {
 handler((Notification) event);
 }
 
 // 
 if (event instanceof Throwable) {
 handlerError((Throwable) event);
 }
 
 reentrantLock.unlock(); 
 }
 
 // }
  52. 52. BlockingQueue<Object> notifyQueue = new LinkedBlockingQueue<>(); class SequentialNotifyObserversPublisher implements Runnable {
 
 final Iterator<Notification> notifies;
 final AtomicBoolean running = new AtomicBoolean(true);
 
 SequentialNotifyObserversRunnable(Iterator<Notification> notifies) {
 this.notifies = notifies;
 }
 
 @Override
 public void run() {
 while (running.get()) {
 if (countObservers() > 0) {
 try {
 notifyQueue.put(notifies.next());
 } catch (Exception error) {
 cancel();
 
 try {
 notifyQueue.put(error);
 } catch (InterruptedException ignore) { }
 }
 }
 
 if (Thread.interrupted()) {
 cancel();
 }
 
 Thread.yield();
 }
 }
 
 void cancel() {
 running.set(false);
 }
 
 }
  53. 53. class MultipleNotificationStreamObservable extends Observable {
 
 final static ExecutorService executor = Executors.newFixedThreadPool(3);
 
 BlockingQueue<Object> notifyQueue = new LinkedBlockingQueue<>();
 Future<?> notifyFuture;
 
 SequentialNotifyObserversPublisher sequentialFeed;
 SequentialNotifyObserversPublisher sequentialFriend;
 
 public MultipleNotificationStreamObservable(NotificationStream stream) {
 this.sequentialFeed = new SequentialNotifyObserversRunnable(stream.feedNotifies());
 this.sequentialFriend = new SequentialNotifyObserversRunnable(stream.friendRecommendationNotifies());
 }
 
 public void subscribe() {
 executor.execute(sequentialFeed);
 executor.execute(sequentialFriend);
 
 notifyFuture = executor.submit(() -> {
 boolean running = true;
 while (running) {
 if (countObservers() > 0) {
 try {
 Object event = notifyQueue.take();
 
 setChanged();
 notifyObservers(event);
 } catch (InterruptedException e) {
 running = false;
 }
 }
 if (Thread.interrupted()) {
 running = false;
 }
 Thread.yield();
 }
 });
 }
 // 
 }
  54. 54. void printUserInfo(String username) {
 NotifyApi notifyApi = new NotifyApi();
 
 NotifyApi.User user = notifyApi.getUser(username);
 Long feedCount = notifyApi.getFeedCount(username);
 Long friendCount = notifyApi.getFriendCount(username);
 
 UserInfo userInfo = new UserInfo(user.getName(), feedCount, friendCount);
 
 System.out.println("User Info");
 System.out.println("name = " + userInfo.getName());
 System.out.println("feedCount = " + userInfo.getFeedCount());
 System.out.println("friendCount = " + userInfo.getFriendCount());
 } 
 
 printUserInfo("fay"); // 1
 printUserInfo("murphy"); // 2
 printUserInfo("nichole"); // 3
  55. 55. void printUserInfo(String username) { … } ExecutorService executorService = Executors.newFixedThreadPool(3); 
 executorService.execute(() -> printUserInfo("fay")); // 1
 executorService.execute(() -> printUserInfo("murphy")); // 2
 executorService.execute(() -> printUserInfo("nichole")); // 3
  56. 56. void printUserInfo(String username) { … } ExecutorService executorService = Executors.newFixedThreadPool(3); 
 executorService.execute(() -> printUserInfo("fay")); // 1
 executorService.execute(() -> printUserInfo("murphy")); // 2
 executorService.execute(() -> printUserInfo("nichole")); // 3 
 executorService.execute(() -> printUserInfo("phillip")); // 4
 executorService.execute(() -> printUserInfo("adrienne")); // 5
 executorService.execute(() -> printUserInfo("nita")); // 6
  57. 57. ExecutorService executorService = Executors.newFixedThreadPool(1); 
 void printUserInfo(String username) {
 CompletableFuture.supplyAsync(() -> notifyApi.getUser(username), executorService)
 .thenCompose(user -> {
 CompletableFuture<Long> feedCountCF = CompletableFuture.supplyAsync(
 () -> notifyApi.getFeedCount(username), executorService);
 
 CompletableFuture<Long> friendCountCF = CompletableFuture.supplyAsync(
 () -> notifyApi.getFriendCount(username), executorService);
 
 return feedCountCF.thenCombineAsync(friendCountCF, (feedCount, friendCount) -> {
 return new UserInfo(user.getName(), feedCount, friendCount);
 }, executorService);
 })
 .thenAccept(userInfo -> {
 System.out.println("User Info");
 System.out.println("name = " + userInfo.getName());
 System.out.println("feedCount = " + userInfo.getFeedCount());
 System.out.println("friendCount = " + userInfo.getFriendCount());
 });
 }
 
 printUserInfo("fay"); // 1
 printUserInfo("murphy"); // 2
 printUserInfo("nichole"); // 3
  58. 58. ExecutorService executorService = Executors.newFixedThreadPool(3); 
 void printUserInfo(String username) {
 // 
 }
 
 
 printUserInfo("fay"); // 1
 printUserInfo("murphy"); // 2
 printUserInfo("nichole"); // 3
 
 printUserInfo("phillip"); // 4
 printUserInfo("adrienne"); // 5
 printUserInfo("nita"); // 6
  59. 59. class NotificationPublisher implements Runnable {
 
 Iterator<Notification> notifies;
 
 NotifyObserversRunnable(Iterator<Notification> notifies) {
 this.notifies = notifies;
 }
 
 @Override
 public void run() {
 boolean running = true;
 while (running) {
 if (countObservers() > 0) {
 try {
 Notification notification = notifies.next();
 
 setChanged();
 notifyObservers(notification);
 } catch (Exception error) {
 running = false;
 
 setChanged();
 notifyObservers(error);
 }
 }
 
 if (Thread.interrupted()) {
 running = false;
 }
 
 Thread.yield();
 }
 }
 
 }
  60. 60. class NotificationPublisher implements Runnable {
 final Iterator<Notification> notifies;
 final AtomicBoolean running = new AtomicBoolean(true); 
 NotifyObserversRunnable(Iterator<Notification> notifies) {
 this.notifies = notifies;
 }
 
 public void run() {
 if (countObservers() > 0) {
 CompletableFuture<Object> completableFuture = new CompletableFuture<>();
 completableFuture.thenAcceptAsync(event -> {
 if (running.get()) {
 setChanged();
 notifyObservers(event);
 }
 schedule(20);
 }, notifyExecutor).exceptionally(throwable -> {
 cancel();
 setChanged();
 notifyObservers(throwable);
 return null;
 });
 try {
 completableFuture.complete(notifies.next());
 } catch (Exception error) {
 completableFuture.completeExceptionally(error);
 }
 }
 schedule(50);
 } 
 void schedule(long millis) {
 if (running.get()) {
 serviceExecutor.schedule(this, millis, TimeUnit.MILLISECONDS);
 }
 } 
 void cancel() {
 running.set(false);
 }
 }
  61. 61. class AsyncMultipleNotificationStreamObservable extends Observable {
 
 final static ScheduledExecutorService serviceExecutor = Executors.newScheduledThreadPool(2);
 final static ScheduledExecutorService notifyExecutor = Executors.newScheduledThreadPool(1);
 
 NotifyObserversRunnable feedPublisher;
 NotifyObserversRunnable friendPublisher;
 
 public AsyncMultipleNotificationStreamObservable(NotificationStream stream) {
 this.feedPublisher = new NotifyObserversRunnable(requireNonNull(stream).feedNotifies());
 this.friendPublisher = new NotifyObserversRunnable(requireNonNull(stream).friendRecommendationNotifies());
 }
 
 public void subscribe() {
 serviceExecutor.schedule(feedPublisher, 10, TimeUnit.MILLISECONDS);
 serviceExecutor.schedule(friendPublisher, 10, TimeUnit.MILLISECONDS);
 }
 
 public void unsubscribe() {
 feedPublisher.cancel();
 friendPublisher.cancel();
 } }
  62. 62. SocketChannel channel = SocketChannel.open();
 channel.configureBlocking(true);
 
 Socket socket = channel.socket();
 socket.connect(new InetSocketAddress("www.naver.com", 80));
 
 BufferedReader input = new BufferedReader(new InputStreamReader(socket.getInputStream()));
 PrintStream output = new PrintStream(socket.getOutputStream());
 
 output.println("GET / HTTP/1.0");
 output.println();
 
 StringBuilder response = new StringBuilder();
 String line = input.readLine();
 while (Objects.nonNull(line)) {
 response.append(line).append("n");
 line = input.readLine();
 
 // body 
 if ("".equals(line)) {
 while (Objects.nonNull(line)) {
 line = input.readLine();
 }
 }
 }
 
 input.close();
 output.close();
  63. 63. PollSelectorImpl WindowsSelectorImpl KQueueSelectorImpl EPollSelectorImpl
  64. 64. Selector selector = Selector.open();
 
 SocketChannel socketChannel = SocketChannel.open();
 socketChannel.configureBlocking(false);
 
 socketChannel.connect(new InetSocketAddress("www.naver.com", 80));
 socketChannel.register(selector, SelectionKey.OP_CONNECT);
 
 while (socketChannel.isOpen()) {
 if (selector.select() > 0) {
 Set<SelectionKey> selectionKeys = selector.selectedKeys();
 Iterator<SelectionKey> iterator = selectionKeys.iterator();
 
 while (iterator.hasNext()) {
 SelectionKey selectionKey = iterator.next();
 
 if (selectionKey.isConnectable()) {
 SocketChannel channel = (SocketChannel) selectionKey.channel(); 
 // 
 } else if (selectionKey.isWritable()) {
 SocketChannel channel = (SocketChannel) selectionKey.channel();
 
 // 
 
 } else if (selectionKey.isReadable()) {
 SocketChannel channel = (SocketChannel) selectionKey.channel();
 
 // 
 
 }
 // 
 iterator.remove();
 }
 }
 }
  65. 65. AsynchronousChannelGroup asynchronousChannelGroup = AsynchronousChannelGroup.withFixedThreadPool(1); AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open(asynchronousChannelGroup); SocketAddress socketAddress = new InetSocketAddress(“www.naver.com”, 80);
 
 asynchronousSocketChannel.connect(socketAddress, null, new CompletionHandler<Void, Void>() {
 @Override
 public void completed(Void v, Void attachment) {
 // 
 asynchronousSocketChannel.write(writeBuffer, null, new CompletionHandler<Integer, Void>() {
 @Override
 public void completed(Integer length, Void attachment) { // 
 asynchronousSocketChannel.read(readBuffer, null, new CompletionHandler<Integer, Void>() {
 @Override
 public void completed(Integer length, Void attachment) { // }
 @Override
 public void failed(Throwable error, Void attachment) {
 // 
 }
 });
 }
 @Override
 public void failed(Throwable error, Void attachment) {
 // 
 }
 });
 }
 @Override
 public void failed(Throwable exc, Void attachment) {
 // 
 }
 });
  66. 66. ✔ Netty(http://netty.io) ✔ gRPG(http://www.grpc.io) ✔ AsyncHttpClient(https://hc.apache.org/)
  67. 67. public FriendRecommendationNotify getRecommendationNotify(String username) throws ServiceOperationException {
 try {
 HttpGet request = new HttpGet(String.format(url, username, processing.name()));
 HttpResponse response = httpClient.execute(request);
 if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
 throw new ServiceOperationException();
 }
 
 return objectMapper.readValue(response.getEntity().getContent(), FriendRecommendationNotify.class);
 } catch (IOException error) {
 throw new ServiceOperationException(error);
 }
 }
  68. 68. public CompletableFuture<FriendRecommendationNotify> getRecommendationNotifyAsync(String username) {
 CompletableFuture<FriendRecommendationNotify> completableFuture = new CompletableFuture<>();
 
 HttpGet request = new HttpGet(String.format(url, username, processing.name()));
 httpAsyncClient.execute(request, new FutureCallback<HttpResponse>() {
 
 @Override
 public void completed(HttpResponse response) {
 try {
 int statusCode = response.getStatusLine().getStatusCode();
 InputStream content = response.getEntity().getContent();
 
 if (statusCode != HttpStatus.SC_OK) {
 completableFuture.completeExceptionally(new ServiceOperationException());
 }
 
 completableFuture.complete(objectMapper.readValue(content, FriendRecommendationNotify.class));
 } catch (IOException error) {
 completableFuture.completeExceptionally(new ServiceOperationException(error));
 }
 }
 
 @Override
 public void failed(Exception error) {
 completableFuture.completeExceptionally(error);
 }
 
 @Override
 public void cancelled() {
 completableFuture.cancel(true);
 }
 
 });
 
 return completableFuture;
 }
  69. 69. @Test
 public void getRecommendationNotify() throws Exception {
 StopWatch stopWatch = new StopWatch("recommendationNotify");
 stopWatch.start();
 
 IntStream.rangeClosed(1, 10)
 .mapToObj(value -> friendService.getRecommendationNotify("user-" + value))
 .forEach(System.out::println);
 
 stopWatch.stop();
 System.out.println();
 System.out.println(stopWatch.prettyPrint());
 }
 
 @Test
 public void getRecommendationNotifyAsync() throws Exception {
 StopWatch stopWatch = new StopWatch("recommendationNotifyAsync");
 stopWatch.start();
 
 IntStream.rangeClosed(1, 10)
 .mapToObj(value -> friendService.getRecommendationNotifyAsync("user-" + value))
 .collect(Collectors.toList())
 .stream()
 .map(CompletableFuture::join)
 .forEach(System.out::println);
 
 stopWatch.stop();
 System.out.println();
 System.out.println(stopWatch.prettyPrint());
 }
  70. 70. class NotificationPublisher implements Runnable {
 
 final Supplier<CompletableFuture<Notification>> notifies;
 final AtomicBoolean running = new AtomicBoolean(true);
 
 NotifyObserversRunnable(Supplier<CompletableFuture<Notification>> notifies) {
 this.notifies = notifies;
 }
 
 @Override
 public void run() {
 if (countObservers() > 0) {
 notifies.get().thenAcceptAsync(event -> {
 if (running.get()) {
 setChanged();
 notifyObservers(event);
 }
 
 schedule(20);
 }, notifyExecutor).exceptionally(throwable -> {
 cancel();
 setChanged();
 notifyObservers(throwable);
 
 return null;
 });
 } else {
 schedule(50);
 }
 }
 
 void schedule(long millis) {
 if (running.get()) {
 serviceExecutor.schedule(this, millis, TimeUnit.MILLISECONDS);
 }
 }
 
 void cancel() {
 running.set(false);
 }
 }
  71. 71. class NonBlockingAsyncMultipleNotificationStreamObservable extends Observable {
 
 final static ScheduledExecutorService serviceExecutor = Executors.newScheduledThreadPool(1);
 final static ScheduledExecutorService notifyExecutor = Executors.newScheduledThreadPool(1);
 
 NotifyObserversRunnable feed;
 NotifyObserversRunnable friend;
 
 public NonBlockingAsyncMultipleNotificationStreamObservable(NotificationStream stream) {
 requireNonNull(stream);
 
 this.feed = new NotifyObserversRunnable(stream::feedNotifyAsync);
 this.friend = new NotifyObserversRunnable(stream::friendRecommendationNotifyAsync);
 }
 
 public void subscribe() {
 serviceExecutor.execute(feed);
 serviceExecutor.execute(friend);
 }
 
 public void unsubscribe() {
 if (nonNull(feed)) feed.cancel();
 if (nonNull(friend)) friend.cancel();
 
 deleteObservers();
 }
 }
  72. 72. class NonBlockingAsyncMultipleNotificationStreamObserver implements Observer, AsyncListener {
 
 final NonBlockingAsyncMultipleNotificationStreamObservable streamObservable;
 final AsyncContext asyncContext;
 
 public NonBlockingAsyncMultipleNotificationStreamObserver(N…Observable streamObservable, AsyncContext asyncContext) {
 this.streamObservable = Objects.requireNonNull(streamObservable);
 this.asyncContext = Objects.requireNonNull(asyncContext);
 }
 
 @Override
 public void update(Observable observable, Object event) {
 if (event instanceof Notification) {
 handler((Notification) event);
 }
 
 if (event instanceof Throwable) {
 handlerError((Throwable) event);
 }
 }
 
 private void handler(Notification notification) {
 try {
 log.info("revised notification/stream/non-blocking-async-concurrency : " + notification.getEvent());
 
 ServletOutputStream outputStream = asyncContext.getResponse().getOutputStream();
 outputStream.write(("event: " + notification.getEvent() + "n").getBytes());
 outputStream.write(("data: " + notification.getData() + "nn").getBytes());
 outputStream.flush();
 } catch (IOException error) {
 throw new DataWriteException(error);
 }
 }
 
 private void handlerError(Throwable error) {
 log.error("error notification/stream/non-blocking-async-concurrency : " + error.getMessage());
 
 streamObservable.unsubscribe();
 asyncContext.complete();
 }
 }
  73. 73. ✔ 비봉쇄 입/출력을 위한 새로운 인터페이스 •ReadListener - 사용 가능한 데이터를 읽을 수 있는 방법 •WriteListener - 데이터 쓰기가 가능한 때를 알 수 있는 방법 ✔ ServletInputStream 에 추가된 기능 •isFinished() •isReady() •setReadListener() ✔ ServletOutputStream 에 추가된 기능 •isReady() •setWriterListener()
  74. 74. ServletInputStream servletInputStream = request.getInputStream();
 servletInputStream.setReadListener(new ReadListener() {
 
 @Override
 public void onDataAvailable() throws IOException {
 // 
 }
 
 @Override
 public void onAllDataRead() throws IOException {
 // 
 }
 
 @Override
 public void onError(Throwable throwable) {
 // 
 }
 
 }); ServletOutputStream servletOutputStream = response.getOutputStream();
 servletOutputStream.setWriteListener(new WriteListener() {
 
 @Override
 public void onWritePossible() throws IOException {
 // 
 }
 
 @Override
 public void onError(Throwable throwable) {
 // 
 }
 
 });
  75. 75. class NonBlockingAsyncMultipleNotificationStreamObserver implements Observer, AsyncListener, WriteListener {
 
 final NonBlockingAsyncMultipleNotificationStreamObservable streamObservable;
 final AsyncContext asyncContext;
 final ServletOutputStream outputStream;
 
 final AtomicInteger counter = new AtomicInteger(1);
 
 public NonBlockingAsyncMultipleNotificationStreamObserver(N…Observable streamObservable, AsyncContext asyncContext) {
 this.streamObservable = Objects.requireNonNull(streamObservable);
 this.asyncContext = Objects.requireNonNull(asyncContext);
 this.outputStream = asyncContext.getResponse().getOutputStream();
 }
 // 
 @Override
 public void onWritePossible() throws IOException {
 // ignore
 }
 
 @Override
 public void onError(Throwable throwable) {
 handlerError(throwable);
 }
 
 private void handler(Notification notification) {
 String content = notification.toContent();
 
 ioExecutor.schedule(() -> write(content.getBytes()), 10, TimeUnit.MILLISECONDS);
 }
 private void handlerError(Throwable error) {
 log.error("error notification/stream/non-blocking-async-concurrency : " + error.getMessage());
 
 streamObservable.unsubscribe();
 asyncContext.complete();
 } // …
  76. 76. // final static ScheduledExecutorService ioExecutor = Executors.newScheduledThreadPool(1); 
 private void write(byte[] data) {
 if (outputStream.isReady()) {
 try {
 outputStream.write(data);
 
 ioExecutor.schedule(this::flush, 10, TimeUnit.MILLISECONDS);
 } catch (IOException error) {
 handlerError(error);
 }
 } else {
 ioExecutor.schedule(() -> write(data), 10, TimeUnit.MILLISECONDS);
 }
 }
 
 private void flush() {
 if (outputStream.isReady()) {
 try {
 outputStream.flush();
 } catch (IOException error) {
 handlerError(error);
 }
 } else {
 ioExecutor.schedule(this::flush, 10, TimeUnit.MILLISECONDS);
 }
 }
 
 }
  77. 77. Ý Ý Ý Ý

×