1

我有这样的事情:

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(...)

可以做到吗?

4

6 回答 6

3

您可以使用自定义类加载器启动应用程序,这将允许您加载和卸载静态变量。

但是,基本上需要这样做是一个非常糟糕的设计。我喜欢将字段设为 final,但如果您想更改它们,则不应将它们设为 final。

于 2010-11-17T20:04:41.357 回答
2

如果您的目标只是重新加载一些配置文件,为什么不实现文件更改监视器呢?

这是关于这个主题的一个很好的教程:

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

我认为您的提议(自动重新启动您的应用程序)会比只关注文件更新更麻烦一些。

于 2010-11-17T18:12:51.427 回答
1

一个更简单的方法就是为此使用静态初始化程序。为什么不直接制作path非最终版本并将其加载main

于 2010-11-17T18:12:31.803 回答
1

我接受彼得劳里的回答,但发布一个完整的例子供任何人使用!

我不会在生产代码中使用它......还有其他方法!

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);
        }
    }
}
于 2010-11-18T10:55:46.777 回答
0

这个结构怎么样

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

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

}

如果您检测到需要重新启动应用程序,请让 runApplication 返回 true。如果是时候退出返回 false;

于 2010-11-17T19:29:01.227 回答
0

如果你有一个 UI 或一个守护进程,所以你可以控制输出到标准输出,你可以在外部制作一个包装器来启动你的程序。

如果退出时程序输出“RESTART”,您可以从此包装器再次重新启动程序。如果没有,它就结束了。

或者,如果您想要纯 Java 方式,您可以使用 Peter Lawrey 在他的帖子中提到的类加载器解决方案。在走这条路之前,您应该真正重新考虑您的设计(如果它是您的代码)并让您的代码能够自行清理。

于 2010-11-17T20:15:12.680 回答