Как я могу запустить "main" в новом процессе на Java?

вопрос довольно простой. Как я могу запустить основной метод в другом процессе java? Теперь я делаю это так:

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

но они попросили меня сделать это не с внешнего .файл jar. В serverstart.jar, очевидно, имеет основной метод ,но его можно вызвать в другом процессе, не вызывая.jar-файл?

Я думаю о чем-то вроде этого:

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

но я не знаю, если что-нибудь подобное существует.

С уважением,

4 ответов


предполагая, что нового потока с новым загрузчиком классов недостаточно (я бы проголосовал за это решение), я понимаю, что вам нужно создать отдельный процесс, который вызывает основной метод в классе, не объявляя его как "основной метод jar" в файле манифеста-так как у вас нет отдельного serverstart.банку больше нет.

в этом случае, вы можете просто позвонить java -cp $yourClassPath your.package.ServerStart, как и для запуска любого приложения java, когда у вас нет (или не хотите использовать) манифест основной класс.


создание нового процесса "java" из java-это не возможно, поскольку два процесса не могут совместно использовать один JVM. (См. вопрос и принял ответ).


если вы можете жить с создания нового Thread вместо Process вы можете сделать это с пользовательским ClassLoader. Это как закрыть вы можете перейти к новому процессу. Все статические и конечные поля будут повторно инициализированы!

также обратите внимание, что "ServerStart класс (для примера ниже) должен находиться в пути к классу текущей выполняющейся JVM):

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

Я бы предложил вызвать shellscript из java и использовать его для запуска нового процесса (если вы вообще не можете жить с другим потоком).


вы можете сделать это с помощью отражения (java.ленг.отразить пакет).

public static void main(String[] args) throws Exception {
    Class c = Class.forName("ServerStart");
    Class[] argTypes = { args.getClass() };
    Method m = c.getMethod("main", argTypes);
    Object passedArgv[] = { args };
    m.invoke(null, passedArgv);
}