如何在Java中的新进程中启动“main”?

这个问题相当简单。如何在另一个java进程中启动main方法?现在我这样做:

startOptions = new String[] {"java", "-jar", "serverstart.jar"};
new ProcessBuilder(startOptions).start();

但是他们要求我不要使用外部.jar文件。serverstart.jar显然有一个main方法,但是是否可以在另一个进程中调用该main方法,而无需调用.jar文件?

我在想这样的事情:

new ProcessBuilder(ServerStart.main(startOptions)).start();

但我不知道是否存在这样的事情。


答案 1

假设一个带有新类加载器的新线程是不够的(不过我会投票支持这个解决方案),我知道你需要创建一个不同的进程来调用类中的main方法,而不会在清单文件中将其声明为“jar main method” - 因为你不再有一个不同的serverstart.jar了。

在这种情况下,您可以简单地调用 ,就像在没有(或不想使用)清单 Main-Class 时运行任何 Java 应用程序一样。java -cp $yourClassPath your.package.ServerStart


答案 2

从java创建新的“java”进程是不可能的,因为两个进程不能共享一个JVM。(请参阅此问题和接受的答案)。


如果您可以忍受创建新的而不是一个,则可以使用自定义.它就像你可以得到一个新的过程一样接近。所有静态字段和最终字段都将重新初始化!ThreadProcessClassLoader

另请注意,该类(对于下面的示例)必须位于当前正在执行的 JVM 的类路径中:"ServerStart

public static void main(String args[]) throws Exception {
    // start the server
    start("ServerStart", "arg1", "arg2");
}

private static void start(final String classToStart, final String... args) {

    // start a new thread
    new Thread(new Runnable() {
        public void run() {
            try {
                // create the custom class loader
                ClassLoader cl = new CustomClassLoader();

                // load the class
                Class<?> clazz = cl.loadClass(classToStart);

                // get the main method
                Method main = clazz.getMethod("main", args.getClass());

                // and invoke it
                main.invoke(null, (Object) args);

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }).start();
}

这是自定义类装入器:

private static class CustomClassLoader extends URLClassLoader {
    public CustomClassLoader() {
        super(new URL[0]);
    }

    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, (CodeSource) null);

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