2013-07-20 4 views
4

Я пытаюсь написать приложение Swing на Java, которое также запускает 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); 
    } 
} 

Помощника-класс, который загружает Google AppEngine Dev-сервер:

// 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 
     } 
    }); 
} 

С этим я получаю некоторые очень странное поведение в отношении свинг Eventloop:

  1. Во-первых, как свинг должен работать: Если я закомментируйте строку DevServer.launch(...) в main(...), запуске приложения, показывает отладки окно, продолжает работать, и когда я закрываю окно отладки, он отключается.
  2. Если я снова добавлю DevServer.launch(...), он запускает сервер, как ожидалось, а затем немедленно завершает работу (возможно, он также отобразил окно отладки ненадолго, но это слишком быстро видно).
  3. Если я переведу DevServer.launch(...) после SwingUtilities.invokeLater(...), он отображает окно отладки, затем запускает сервер, и когда сервер встает, он немедленно завершает работу.
  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», чтобы доказать свою точку зрения. Shallowing никогда не бывает хорошей идеей –

+0

@ c.s. Согласовано. Фактически я определил объект 'ShouldNeverHappenException' для себя именно по этой причине, который я всегда использую. Я просто удалил его из образца кода, так как я не хотел публиковать еще один класс для полноты ... –

ответ

1

Элементы № 4 и № 5 являются фактически ожидаемым поведением. Приложение Java/Swing не останавливается, когда находится последнее окно Swing, но когда последний поток прекращает выполнение. Эти два условия эквивалентны для однопоточных приложений, но не для многопоточных.

Что касается № 1, № 2 и № 3: просматривая код сервера AppEngine Dev, я заметил, что там было достаточно System.exit(int) звонков. Один из них, вероятно, является виновником.Если код, который вы показываете, является релевантным, тогда оскорбительное System.exit, скорее всего, будет вызвано в ответ на соединение, установленное после if (!waitFor) return; (из-за # 4).

+0

Возможно, вы правы, что # 4 вызван некоторым потоком, открытым открытым сервером Dev, но если # 2 и # 3 были вызваны одним из 'System.exit (...)' 's в Dev-сервере, почему бы и # 4 и # 5 не уйти сразу же? –

+0

# 4 и # 5, похоже, не подключаются к серверу Dev. По крайней мере, не в коде, который вы опубликовали. Я предполагаю, что запуск сервера Dev (что-нибудь выше 'if (! WaitFor) return;') отлично, но что-то в обработке соединения с сервером Dev (которое запускается только в том случае, если 'waitFor' является' true') вызывает Выполните вызов 'System.exit'. – Daan

+0

Странно то, что если я положу 'System.out.println (...)' после 'DevServer.launch (args, true)', он будет выполнен, поэтому действие соединения в одиночку не убивает программа. Кроме того, если я поместил 'Thread.sleep (10000)' в конце метода 'main (...)' в случае # 2 или # 3, сервер будет работать в течение 10 секунд и обрабатывать запросы просто отлично, но как вскоре, поскольку метод 'main (...)' фактически завершается, приложение завершает работу. Таким образом, выключение приложения действительно вызвано завершением метода 'main (...)', как если бы цикл событий Swing больше не выполнялся ... –

Смежные вопросы