글
스윙책에서 이벤트처리 스레드를 강조했기에 (java.awt.EventDispatchThread)
이번 기회에 분석하자 해서 봤더만... 머리아픔..
63 class More ...EventDispatchThread extends Thread {
64
65 private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread");
66
67 private EventQueue theQueue; // 이벤트큐 구현 코드는 제일 아래쪽에 (자기=스레드가 처리할 작업거리를 필드로
갖고있다..
68 private boolean doDispatch = true;
69 private boolean threadDeathCaught = false;
70
71 private static final int ANY_EVENT = -1;
72
73 private Vector<EventFilter> eventFilters = new Vector<EventFilter>();//체인오브 리스폰스빌리티처럼,.. 필터개념
//으로 이벤트 검사
74
75 More ...EventDispatchThread(ThreadGroup group, String name, EventQueue queue) {
76 super(group, name);
77 setEventQueue(queue); //aggregation.. 내 경운 전에 worker와 work를 association으로 해서 worker.setWork(work)
78 }
79
80 /*
81 * Must be called on EDT only, that's why no synchronization
82 */
83 public void More ...stopDispatching() {
84 doDispatch = false;
85 }
86
//아래가 기본 동작 run()
87 public void More ...run() {
88 while (true) {
89 try {
90 pumpEvents(new Conditional() {
91 public boolean More ...evaluate() {
92 return true;
93 }
94 });
95 } finally { //리턴을 해도 finally는 무조건 실행됨.(내가 전에 이것땜에 당황했었음)
96 EventQueue eq = getEventQueue();
//아래는 run의 while(true) 종료 조건임 이게 finally구문 안에 있는것을 이해할것!
97 if (eq.detachDispatchThread(this) || threadDeathCaught) {
98 break;
99 }
100 }
101 }
102 }
103
104 void More ...pumpEvents(Conditional cond) {
105 pumpEvents(ANY_EVENT, cond);
106 }
107
108 void More ...pumpEventsForHierarchy(Conditional cond, Component modalComponent) {
109 pumpEventsForHierarchy(ANY_EVENT, cond, modalComponent);
110 }
111
112 void More ...pumpEvents(int id, Conditional cond) {
113 pumpEventsForHierarchy(id, cond, null);
114 }
115
116 void More ...pumpEventsForHierarchy(int id, Conditional cond, Component modalComponent) {
117 pumpEventsForFilter(id, cond, new HierarchyEventFilter(modalComponent));
118 }
119
120 void More ...pumpEventsForFilter(Conditional cond, EventFilter filter) {
121 pumpEventsForFilter(ANY_EVENT, cond, filter);
122 }
166 boolean More ...pumpOneEventForFilters(int id) {
167 AWTEvent event = null;
168 boolean eventOK = false;
169 try {
170 EventQueue eq = null;
171 EventQueueDelegate.Delegate delegate = null;
172 do {
173 // EventQueue may change during the dispatching
174 eq = getEventQueue();
//아래는 getDelegate() 메서드에서 뭘하는지 확인 필요..(AppContext는 프로그램을 의미하는 전역//객체라 생각하는게 편할듯)//프로그램별로 이벤트 처리 담당하는 녀석들이 set에 들어있나봄.. swing의 컴포넌트들도 그렇던데..39 public static Delegate More ...getDelegate() {40 return41 (Delegate) AppContext.getAppContext().get(EVENT_QUEUE_DELEGATE_KEY);42 }
175 delegate = EventQueueDelegate.getDelegate();
176
//이벤트 처리할 delegate를 얻었으니.. 큐에서 이벤트 꺼내오기.
177 if (delegate != null && id == ANY_EVENT) {
178 event = delegate.getNextEvent(eq);
179 } else {
180 event = (id == ANY_EVENT) ? eq.getNextEvent() : eq.getNextEvent(id);
181 }
182
//아래 로직을 보니.. eventOK = false; 코드가 눈에 띄는데.. 여러 필터단에서 해당 이벤트가//처리할 이벤트인지를 검증하는듯..
183 eventOK = true;
184 synchronized (eventFilters) {
185 for (int i = eventFilters.size() - 1; i >= 0; i--) {
186 EventFilter f = eventFilters.get(i);
187 EventFilter.FilterAction accept = f.acceptEvent(event);
188 if (accept == EventFilter.FilterAction.REJECT) {
189 eventOK = false;
190 break;
191 } else if (accept == EventFilter.FilterAction.ACCEPT_IMMEDIATELY) {
192 break;
193 }
194 }
195 }
//필터로도 부족해서 다른 메서드를 통해 이벤트인지를 확인
196 eventOK = eventOK && SunDragSourceContextPeer.checkEvent(event);
197 if (!eventOK) {
198 event.consume(); //말그대로.. 이벤트를 처리한달까? 소모시키기.. 아래처럼 구현
418 protected void More ...consume() {419 switch(id) {420 case KeyEvent.KEY_PRESSED:421 case KeyEvent.KEY_RELEASED:422 case MouseEvent.MOUSE_PRESSED:423 case MouseEvent.MOUSE_RELEASED:424 case MouseEvent.MOUSE_MOVED:425 case MouseEvent.MOUSE_DRAGGED:426 case MouseEvent.MOUSE_ENTERED:427 case MouseEvent.MOUSE_EXITED:428 case MouseEvent.MOUSE_WHEEL:429 case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED:430 case InputMethodEvent.CARET_POSITION_CHANGED:431 consumed = true;432 break;433 default:434 // event type cannot be consumed435 }436 }
199 }
200 }
//처리할 이벤트가 아니면.. 무한루프 돌면서 시간 때우기.. (물론 스레드임으로 인터럽트 발생하면//다른 스레드에게 실행권 넘어감.
201 while (eventOK == false);
202
203 if (eventLog.isLoggable(PlatformLogger.FINEST)) {
204 eventLog.finest("Dispatching: " + event);
205 }
206
//아래 부분이 핵심인듯 한데.. 이해가 안됨.. 저 메서드들도 숨어있고..
207 Object handle = null;
208 if (delegate != null) {
209 handle = delegate.beforeDispatch(event);
210 }
211 eq.dispatchEvent(event);
212 if (delegate != null) {
213 delegate.afterDispatch(event, handle);
214 }
215
216 return true;
217 }
218 catch (ThreadDeath death) {
219 threadDeathCaught = true;
220 return false;
221
222 }
223 catch (InterruptedException interruptedException) { //프로그램 내의 모든 스레드를 회수 = 프로그램 종료
224 return false; // AppContext.dispose() interrupts all
225 // Threads in the AppContext
226
227 }
228 catch (Throwable e) {
229 processException(e);
230 }
231
232 return true;
233 }
**************************************************************
235 private void More ...processException(Throwable e) {
236 if (eventLog.isLoggable(PlatformLogger.FINE)) {
237 eventLog.fine("Processing exception: " + e);
238 }
239 getUncaughtExceptionHandler().uncaughtException(this, e); //분석하고 싶은데 메서드 못찾겠음..
240 }
***************************************************************
//우선순위큐로 이벤트들을 모아놓고, 스레드 세이프하게 fifo방식으로 처리
101 public class More ...EventQueue {
102
103 // From Thread.java
104 private static int threadInitNumber;
105 private static synchronized int More ...nextThreadNum() {
106 return threadInitNumber++;
107 }
108
109 private static final int LOW_PRIORITY = 0;
110 private static final int NORM_PRIORITY = 1;
111 private static final int HIGH_PRIORITY = 2;
112 private static final int ULTIMATE_PRIORITY = 3;
113
114 private static final int NUM_PRIORITIES = ULTIMATE_PRIORITY + 1;
115
116 /*
117 * We maintain one Queue for each priority that the EventQueue supports.
118 * That is, the EventQueue object is actually implemented as
119 * NUM_PRIORITIES queues and all Events on a particular internal Queue
120 * have identical priority. Events are pulled off the EventQueue starting
121 * with the Queue of highest priority. We progress in decreasing order
122 * across all Queues.
123 */
124 private Queue[] queues = new Queue[NUM_PRIORITIES]; //스레드 우선순위별로 관리하는듯
125
126 /*
127 * The next EventQueue on the stack, or null if this EventQueue is
128 * on the top of the stack. If nextQueue is non-null, requests to post
129 * an event are forwarded to nextQueue.
130 */
131 private EventQueue nextQueue; //자신을 가리켜? 뭐지?? 연결리스트인가? 이벤트큐 연결 리스트 자료구조?
132
133 /*
134 * The previous EventQueue on the stack, or null if this is the
135 * "base" EventQueue.
136 */
137 private EventQueue previousQueue; //이전을??
138
139 /*
140 * A single lock to synchronize the push()/pop() and related operations with
141 * all the EventQueues from the AppContext. Synchronization on any particular
142 * event queue(s) is not enough: we should lock the whole stack.
143 */
144 private final Lock pushPopLock; //스레드 세이프 (동시에 pop 불가 = 하나의 이벤트당 하나의 스레드)
145 private final Condition pushPopCond;
146
147 /*
148 * Dummy runnable to wake up EDT from getNextEvent() after
149 push/pop is performed
150 */
151 private final static Runnable dummyRunnable = new Runnable() {
152 public void More ...run() {
153 }
154 };
생략..
*****************************************************************8
249 private static class More ...HierarchyEventFilter implements EventFilter {
250 private Component modalComponent;
251 public More ...HierarchyEventFilter(Component modalComponent) {
252 this.modalComponent = modalComponent;
253 }
254 public FilterAction More ...acceptEvent(AWTEvent event) {
255 if (modalComponent != null) {
256 int eventID = event.getID();
257 boolean mouseEvent = (eventID >= MouseEvent.MOUSE_FIRST) &&
258 (eventID <= MouseEvent.MOUSE_LAST);
259 boolean actionEvent = (eventID >= ActionEvent.ACTION_FIRST) &&
260 (eventID <= ActionEvent.ACTION_LAST);
261 boolean windowClosingEvent = (eventID == WindowEvent.WINDOW_CLOSING);
262 /*
263 * filter out MouseEvent and ActionEvent that's outside
264 * the modalComponent hierarchy.
265 * KeyEvent is handled by using enqueueKeyEvent
266 * in Dialog.show
267 */
268 if (Component.isInstanceOf(modalComponent, "javax.swing.JInternalFrame")) {
269 /*
270 * Modal internal frames are handled separately. If event is
271 * for some component from another heavyweight than modalComp,
272 * it is accepted. If heavyweight is the same - we still accept
273 * event and perform further filtering in LightweightDispatcher
274 */
275 return windowClosingEvent ? FilterAction.REJECT : FilterAction.ACCEPT;
276 }
277 if (mouseEvent || actionEvent || windowClosingEvent) {
278 Object o = event.getSource();
279 if (o instanceof sun.awt.ModalExclude) {
280 // Exclude this object from modality and
281 // continue to pump it's events.
282 return FilterAction.ACCEPT;
283 } else if (o instanceof Component) {
284 Component c = (Component) o;
285 // 5.0u3 modal exclusion
286 boolean modalExcluded = false;
287 if (modalComponent instanceof Container) {
288 while (c != modalComponent && c != null) {
289 if ((c instanceof Window) &&
290 (sun.awt.SunToolkit.isModalExcluded((Window)c))) {
291 // Exclude this window and all its children from
292 // modality and continue to pump it's events.
293 modalExcluded = true;
294 break;
295 }
296 c = c.getParent();
297 }
298 }
299 if (!modalExcluded && (c != modalComponent)) {
300 return FilterAction.REJECT;
301 }
302 }
303 }
304 }
305 return FilterAction.ACCEPT;
306 }
307 }
'자바se api > swing' 카테고리의 다른 글
스윙.. (0) | 2014.01.02 |
---|---|
스윙의 기본적인 멀티스레드 처리방식 (0) | 2014.01.02 |
propertyEditor vs ConversionService + 토비의 스프링? (0) | 2014.01.02 |
자바 스윙 겁나 복잡하고 방대함... (0) | 2014.01.02 |
RECENT COMMENT