2013-07-20 169 views
4

我正嘗試在Java中編寫Swing應用程序,該應用程序也運行Google AppEngine Dev-Server(請參閱Developing a Java Application that uses an AppEngine database)並且遇到Swing Eventloop出現的奇怪問題。Java Swing應用程序意外終止

我有以下兩類:

一個調試窗口,這將最終接收日誌消息,等:

public class DebugWindow { 

    private static JFrame debugWindow = null; 
    private static JTextArea debugContent = null; 

    public static void show() { 
     debugWindow = new JFrame("Debug"); 
     debugWindow.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     debugContent = new JTextArea("Debug messages go here!"); 
     debugWindow.add(debugContent, BorderLayout.CENTER); 
     debugWindow.pack(); 
     debugWindow.setVisible(true); 
    } 
} 

加載了谷歌的AppEngine開發,服務的輔助類:

// other imports 
import com.google.appengine.tools.development.DevAppServerMain; 

public class DevServer { 
    public static void launch(final String[] args, boolean waitFor) { 
     Logger logger = Logger.getLogger(""); 
     logger.info("Launching AppEngine server..."); 
     Thread server = new Thread() { 
      @Override 
      public void run() { 
       try { 
        DevAppServerMain.main(args); // run DevAppServer 
       } catch (Exception e) { e.printStackTrace(); } 
      } 
     }; 
     server.setDaemon(true); // shut down server when rest of app completes 
     server.start();   // run server in separate thread 
     if (!waitFor) return; // done if we don't want to wait for server 
     URLConnection cxn; 
     try { 
      cxn = new URL("http://localhost:8888").openConnection(); 
     } catch (IOException e) { return; } // should never happen 
     boolean running = false; 
     while (!running) { 
      try { 
       cxn.connect(); // try to connect to server 
       running = true; 
      } catch (Exception e) {} 
     } 
     logger.info("Server running."); 
    } 
} 

main(...)方法是這樣的:

public static void main(final String[] args) throws Exception { 
    DevServer.launch(args, true); // launch and wait for AppEngine dev server 
    SwingUtilities.invokeLater(new Runnable() { 
     @Override 
     public void run() { 
      DebugWindow.show(); // create and show debug window 
     } 
    }); 
} 

有了這個我收到有關Swing的事件循環一些非常奇怪的現象:

  1. 首先,搖擺的方式應該工作:如果我註釋掉線DevServer.launch(...)main(...),應用程序啓動,顯示了調試窗口繼續運行,當我關閉調試窗口時,它關閉。
  2. 如果我重新添加DevServer.launch(...),它會按預期啓動服務器,然後立即退出(它可能還會短暫顯示調試窗口,但看起來太快了)。
  3. 如果我在SwingUtilities.invokeLater(...)之後移動DevServer.launch(...)行,它會顯示調試窗口,然後啓動服務器,並在服務器啓動時立即退出。
  4. 現在它變得非常奇怪:如果我將行更改爲DevServer.launch(args, false),即我不等待服務器實際啓動,但只是讓我的main(...)方法立即完成,調試窗口顯示,服務器正確加載,應用程序保持運行,但如果關閉調試窗口不會退出?!
  5. 如果我再將JFrame.DISPOSE_ON_CLOSE更改爲JFrame.EXIT_ON_CLOSE,則調試窗口顯示服務器正確加載,應用程序保持運行,如果關閉調試窗口,它會正確退出。

任何想法這裏的Swing事件循環發生了什麼?我很難過......是否會導致Swing事件循環提前終止(場景2和3)?多線程應用程序是否阻止Swing檢測上次放置的窗口(方案4)?

僅供參考,here is the source of the Google AppEngine Dev Server

+0

當您捕捉到「應該永遠不會發生」的異常時, IOException',將它重新拋出爲'RuntimeException'總是一個好主意,只是爲了證明你的觀點。淺色從來不是一個好主意 –

+0

@ c.s。同意。我實際上爲我自己定義了一個'ShouldNeverHappenException'對象,我總是使用它。我只是從代碼示例中刪除它,因爲我不想發佈另一個類的完整性... –

回答

1

項目#4和#5實際上是預期的行爲。當處理最後一個Swing窗口時,Java/Swing應用程序不會停止,但當最後一個線程停止執行時。這兩個條件對於單線程應用程序是等同的,但對於多線程應用程序則不同。

至於#1,#2和#3:通過AppEngine Dev Server代碼查看,我注意到有相當數量的System.exit(int)調用。其中之一可能是罪魁禍首。如果您顯示的代碼是相關的,那麼可能會調用System.exit以響應在if (!waitFor) return;(由於#4)後建立的連接

+0

你可能是正確的#4是由開發服務器保持打開的某個線程引起的,但如果#2和#3是由開發服務器中的一個'System.exit(...)'引起的,爲什麼#4和#5不會立即退出? –

+0

#4和#5似乎並沒有實際連接到Dev服務器。至少不在您發佈的代碼中。我的猜測是開發服務器的啓動(if(!waitFor)return;')之上的任何東西都可以,但Dev服務器的連接處理中的某些事情(只有在'waitFor'爲'true'時纔會觸發)導致它發出'System.exit'調用。 – Daan

+0

奇怪的是,如果我在'DevServer.launch(args,true)'之後放置一個'System.out.println(...)',它會被執行,所以單獨連接的行爲不會殺死程序。另外,如果我在#2或#3的'main(...)'方法末尾放置了一個'Thread.sleep(10000)',服務器將運行10秒並處理請求就好了,但是作爲一旦'main(...)'方法實際終止,應用程序就退出。因此,應用程序關閉實際上是由'main(...)'方法的完成觸發的,就好像Swing事件循環不再運行一樣... –