일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 완전 탐색
- 이분 탐색
- 유레카
- 서비스 디스커버리
- 주울
- spring cloud
- Gradle
- 트리
- docker-compose
- ZuulFilter
- 구현
- 플로이드 와샬
- 다익스트라
- 메모이제이션
- Logback
- 도커
- spring boot
- 백트래킹
- 이분 매칭
- 달팽이
- dp
- 스프링 시큐리티
- 비트마스킹
- Java
- 구간 트리
- Zuul
- 스택
- Spring Cloud Config
- BFS
- 게이트웨이
- Today
- Total
목록Toy Project (35)
Hello, Freakin world!
ConnectionLoop 는 서버와의 연결에 실패했을 때의 상황을 처리하기 위해 구현했다. 사용자의 커맨드에 따라 다시 연결을 시도할지, 연결을 그만두고 애플리케이션을 종료할지 선택할 수 있다. 코드 private void connectionLoop() { while(true) { System.out.println("연결 중..."); Optional socketChannelOpt = Optional.ofNullable(channelManager.connect()); if(socketChannelOpt.isPresent()){ boolean isConnected = channelManager.finishConnect(socketChannelOpt.get()); if(isConnected) { Syste..
이제까지는 필요한 기능에 따라 클래스 레벨의 목표에 맞춰서 코딩했다. 어느 정도 뼈대가 갖춰졌으니, 목표를 서버와 클라이언트의 전체적인 동작에 맞추어보자. 첫 번째 목표 두 명의 클라이언트가 서버에 연결되고 각각 클라이언트는 서버와 연결되면 콘솔에 메세지를 표시한다. 서버 역시도 콘솔에 메세지를 표시한다.
메서드 설명 - getHandlerMap() 이 메서드는 클래스 내에 존재하는 @Event 애너테이션이 달린 메서드들을 자신의 메서드명(event명)으로 매핑한 맵을 반환한다. (내가 임의로 메서드명과 이벤트명이 같아지도록 구현함) 그 과정에서 Stream api와 Reflection api를 사용했다. - delegate() handler 맵을 순회하면서 전달받은 key에 포함된 eventName 값을 이용해 이와 일치하는 Method를 찾는다. 그리고 찾은 method를 호출한다. 또 다른 중요 키포인트 이 클래스는 외부에 delegate() 만을 노출한다. 직접적으로 핸들러가 호출되는 일은 없다. 이는 클래스 사용자가 어떤 api를 쓸지 고민할 필요가 없게 만든다. 후~ 뼈대 작업이 끝났다. 이제 ..
(갤럭시 탭을 구입해서 처음 작성해서 올리는 그림이다. 지금까지 직접 필기한 그림을 올리거나 마우스로 그림판에 그려 올렸는데 삶의 질이 올라간 기분!!) EventController와 같은 컨테이너 클래스를 둔 이유 결론부터 말하자면 핸들러의 유지보수성 때문이다. 지금 당장은 콘솔을 기반으로 한 채팅앱이라 EventHandler 의 핸들러가 처리한 결과를 바로 콘솔에 띄워서 바로 반영할 수 있다. 하지만 이 앱이 GUI 기반의 앱으로 확장될 가능성이 있다면? 핸들러에서 처리한 결과를 어떻게든 반영하기 위해 핸들러는 UI 객체에 대해 알아야 한다. UI를 컨트롤하는 객체는 main context에서 객체를 생성할 터인데 이를 주입받아 이벤트 컴포넌트 들과의 관계들을 설정하는 컨테이너 객체도 필요한 것이다...
selectionKey 객체는 이벤트와 함께 넘어오며 이벤트가 발생한 채널 객체 정보를 가지고 있다. event 로 감쌌지만 이벤트라는 개념을 설명하기 위한 가상의 객체다. (그런데 생각해보니 Event 클래스를 만들어두는게 더 나을지도 모른다는 생각이 들었다. 지금은 넘어가자) EventLoop 스레드에서 selectionKey 객체를 핸들러의 delegate 메서드의 파라미터로 넘겼었다. delegate 메서드는 핸들러에 내부의 메서드들 중 적절한 메서드와 해당 키를 매핑한다. 이런 일대다의 관계에서 매핑을 구현하기 위해 if문을 사용하면 결국 '다'부분의 가짓수가 늘어남에 따라 점점 가독성이 떨어지고 유지보수하기 어려운 코드가 탄생한다. 이를 해결하기 위해 애너테이션을 이용하자. 예를 들면, 스프링..
public class EventLoop extends Thread{ Selector selector; EventHandler eventHandler = new EventHandler(); Logger logger = Logger.getLogger(EventLoop.class.getCanonicalName()); public EventLoop(Selector selector) { this.selector = selector; Thread.currentThread().setDaemon(true); } @Override public void run() { logger.entering("EventLoop", "run"); while(true) { try { selector.select(); logger.fin..
import ... public class SelectorManager { Selector selector; public synchronized Selector getSelector(){ if(!selector.isOpen() | selector == null ) { open(); return selector; } return selector; } public void close(){ try { selector.close(); } catch (IOException e) { e.printStackTrace(); } } private void open() { try { selector = Selector.open(); } catch (IOException e) { e.printStackTrace(); } }..
EventContainer - 이벤트 최상위 계층의 컨테이너 클래스다. 필드 객체에 필요한 객체를 주입한는 역할을 한다. EventLoop - 이벤트를 받아서 계속 처리하기 위한 클래스다. EventHandler - 이벤트에 대한 핸들러를 위한 클래스다. SelectManager - selector 객체의 생성과 파괴의 책임을 담당하는 클래스. selector 객체를 무조건 이 클래스를 통해 제공받는다.
아직 채팅방같은 클라이언트들끼리의 선별적인 대화는 x 서버가 최대 수용할 수 있는 클라이언트 수는 2명이라고 가정한다. 클라이언트는 상대 클라이언트가 접속했을 경우와 나갔을 경우 메세지를 통해 알 수 있다. 채팅 메세지등 모든 네트워크 요청은 서버를 통해 이루어진다. 자, 이제 두 명의 사용자가 대화가 가능하도록 해보자!!
다시 ClientChannelManager 클래스로 돌아와서 작성했던 기능들의 단위테스트를 작성해보자. 아래는 ClientChannelManager 클래스의 코드다. import ... /* 이 클래스의 책임은 어디까지인가? 단순하게 채널 객체의 생성과 반환만을 책임진다. */ public class ClientChannelManager { private SocketChannel socketChannel; private Logger logger = Logger.getLogger(ClientChannelManager.class.getCanonicalName()); private SocketAddress serverAddress; public ClientChannelManager(){} public sync..