Перезагрузите себя - могу ли я все заново инициализировать? - PullRequest
2 голосов
/ 17 ноября 2010

У меня есть что-то вроде этого:

public static final String path;
static {
    path = loadProperties("config.conf").getProperty("path");
}

public static void main(String... args) {

    // ... do stuff (starting threads that reads the final path variable)

    // someone want's to update the path (in the config.conf file)
    restart(); // ???
}

Я хочу повторно инициализировать JVM, снова вызывая статический инициализатор, а затем main(...)!

Можно ли это сделать?

Ответы [ 6 ]

3 голосов
/ 17 ноября 2010

Вы можете запустить свое приложение, используя пользовательский загрузчик классов, это позволит вам загружать и выгружать статические переменные.

Тем не менее, в принципе это очень плохой дизайн, чтобы сделать это. Мне нравится делать поля окончательными, но вы не должны делать их окончательными, если хотите изменить их.

2 голосов
/ 18 ноября 2010

Я принимаю Питер Лоури ответ, но опубликуйте полный пример, чтобы кто-нибудь мог его использовать!

Я не собираюсь использовать это в рабочем коде ...другие способы сделать это!

public class Test {

    public static void main(String args[]) throws Exception {
        start();
        Thread.sleep(123);
        start();
    }

    private static void start() throws Exception {

        ClassLoader cl = new ClassLoader(null) {
            protected java.lang.Class<?> findClass(String name) 
            throws ClassNotFoundException {
                try{
                    String c = name.replace('.', File.separatorChar) +".class";
                    URL u = ClassLoader.getSystemResource(c);
                    String classPath = ((String) u.getFile()).substring(1);
                    File f = new File(classPath);

                    FileInputStream fis = new FileInputStream(f);
                    DataInputStream dis = new DataInputStream(fis);

                    byte buff[] = new byte[(int) f.length()];
                    dis.readFully(buff);
                    dis.close();

                    return defineClass(name, buff, 0, buff.length, null);

                } catch(Exception e){
                    throw new ClassNotFoundException(e.getMessage(), e);
                }
            }
        };

        Class<?> t = cl.loadClass("Test$Restartable");
        Object[] args = new Object[] { new String[0] };
        t.getMethod("main", new String[0].getClass()).invoke(null, args);
    }

    public static class Restartable {

        private static final long argument = System.currentTimeMillis();

        public static void main(String args[]) throws Exception {
            System.out.println(argument);
        }
    }
}
2 голосов
/ 17 ноября 2010

Если ваша цель - просто перезагрузить некоторые файлы конфигурации, почему бы не реализовать монитор изменений файлов?

Вот хорошее руководство по этому вопросу:

http://download.oracle.com/javase/tutorial/essential/io/notification.html

Я думаю, что то, что вы предлагаете (автоматический перезапуск приложения), было бы немного более громоздким, чем просто наблюдение за обновлениями файлов.

1 голос
/ 17 ноября 2010

Более простой подход - просто , а не , чтобы использовать статический инициализатор для этого.Почему бы просто не сделать path не финальным и загрузить его в main?

0 голосов
/ 17 ноября 2010

Если у вас есть пользовательский интерфейс или демон, чтобы вы могли контролировать вывод в stdout, вы можете создать оболочку снаружи, которая запускает вашу программу.

Если программа при выходе выдает «RESTART», вы можете перезапустить вашу программу снова из этой оболочки. Если нет, это просто заканчивается.

Или, если вам нужен чистый Java-способ, вы можете воспользоваться решением для загрузчиков классов, как упомянул Питер Лоури в своем посте. Прежде чем идти по этому пути, вы должны по-настоящему переосмыслить свой дизайн (если это ваш код) и сделать свой код способным к самоочищению.

0 голосов
/ 17 ноября 2010

как насчет этой структуры

public static void main(String... args) {

    boolean restart = true;
    while (restart )
    {
        retart = runApplication();
    }

}

Если вы когда-нибудь обнаружите необходимость перезапустить ваше приложение, пусть runApplication вернет true. Если пора выходить, верните false;

...