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



这个问题很简单。如何在另一个 Java 进程中启动主方法?现在我这样做:

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

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

我在想这样的事情:

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

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

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

在这种情况下,您可以简单地调用 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);
        }
    }
}

我建议从java调用shellscript并使用它来启动新进程(如果您根本无法忍受另一个线程)。

我将在这里回答如何在没有弹簧:)的情况下创建多进程应用程序。使用spring,您可以通过xml配置来做到这一点。多线程是另一回事,这是多进程

创建一个 JavaProces 类,如下所示。您可以在您的环境中存储此类的对应 XML/JSON。然后从Runtime.getRuntime().exec(processRunnerString);开始您的过程,

您应该首先找到java.exevm args,然后分别设置-classpath mainClassargs

最后你会得到类似java JRE\java.exe-classpath的东西。 .;*;lib* AClass arg1 - Dprop=val

您可以使用JMX与其他进程进行通信。

import java.util.Dictionary;
import java.util.List;
public class JavaProcess {
    private String mainClass;
    private Dictionary<String, String> vmParameters;
    private List<String> classPath;
    private List<String> mainArgs;
    public String getMainClass() {
        return mainClass;
    }
    public void setMainClass(String mainClass) {
        this.mainClass = mainClass;
    }
    public Dictionary<String, String> getVmParameters() {
        return vmParameters;
    }
    public void setVmParameters(Dictionary<String, String> vmParameters) {
        this.vmParameters = vmParameters;
    }
    public List<String> getClassPath() {
        return classPath;
    }
    public void setClassPath(List<String> classPath) {
        this.classPath = classPath;
    }
    public List<String> getMainArgs() {
        return mainArgs;
    }
    public void setMainArgs(List<String> mainArgs) {
        this.mainArgs = mainArgs;
    }
}

MainRunner 应用程序,您可以从 配置文件。我刚刚在这里创建了一个虚拟进程,以防万一 错误我停止它从进程的回调。

    //process
    JavaProcess jp = new JavaProcess();
    //java class
    jp.setMainClass("com.hmg.vidapter.run.DriverLauncher");
    //main args[]
    List<String> mainArgsList = new ArrayList<String>();
    mainArgsList.add("ABC1 ARG2 ARG3 ARGN");
    jp.setMainArgs(mainArgsList);
    //-classpath
    List<String> classPath = new ArrayList<String>();
    classPath.add("*");
    classPath.add("libs\*");
    classPath.add("repo\*");
    jp.setClassPath(classPath);
    //-Dvm args.
    Dictionary<String, String> vmArgs = new Hashtable<String, String>();
    vmArgs.put("-Dcom.sun.management.jmxremote", "");
    vmArgs.put("-Dcom.sun.management.jmxremote.authenticate=false", "");
    vmArgs.put("-Dcom.sun.management.jmxremote.port=1453", "");
    vmArgs.put("-Dcom.sun.management.jmxremote.ssl=false", "");
    jp.setVmParameters(vmArgs);
    String params = JSONUtils.convertToJSON(jp);
    System.out.println(params);
    StringBuilder sb = new StringBuilder(""" + getJavaExecutablePath()+ """);
    sb.append(" ");
    Enumeration<String> vmaEnum = vmArgs.keys();
    while (vmaEnum.hasMoreElements()) {
        String key = vmaEnum.nextElement();
        sb.append(key + " ");
        String val=vmArgs.get(key);
        if(val!=null && !val.isEmpty())
        {
            sb.append(val + " ");
        }
    }
    sb.append(" -classpath ");
    List<String> cps = jp.getClassPath();
    for (String cp : cps) {
        sb.append(cp+";");
    }
    sb.append(" ");             
    sb.append(jp.getMainClass());
    sb.append(" ");
    List<String> mainArgs = jp.getMainArgs();
    for (String ma : mainArgs) {
        sb.append(ma+" ");
    }
    System.out.println(sb.toString());
    Process p = Runtime.getRuntime().exec(sb.toString());
    //write output
    InputStreamReader isrO = new InputStreamReader(p.getInputStream());
    BufferedReader brO = new BufferedReader(isrO);
    String callBackO = brO.readLine();
    if (callBackO!=null)
    {
        System.out.println("Application Output: " + callBackO);         
    }
    //write errput
    InputStreamReader isr = new InputStreamReader(p.getErrorStream());
    BufferedReader br = new BufferedReader(isr);
    String callBack = br.readLine();
    if (callBack!=null)
    {
        System.err.println("Application Error: "+ callBack);
        //you can do whatever you want if you don't wanna stop it
        p.destroyForcibly();
    }

从java.home env.变量中确定java.exe的位置。

private static String getJavaExecutablePath(){
        String javaHome = System.getProperty("java.home");
        File f = new File(javaHome);
        f = new File(f, "bin");
        f = new File(f, "java.exe");
        return f.getAbsolutePath();
    }
您可以使用

Reflection(java.lang.reflect package)来执行此操作。

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

相关内容

  • 没有找到相关文章

最新更新