Java - 在另一个进程中启动另一个类'main

时间:2014-01-17 19:10:44

标签: java netbeans runtime main processbuilder

我需要一种干净的方式来启动带有GUI的Java程序的许多实例,我想以编程方式执行它。我想运行的“程序”只是一个.class文件(一个带有main方法的已编译的.java文件),它应该显示一个GUI并独立于其他文件运行(作为它自己的进程)。我还需要传递一些参数。

检查EDIT5以获取完整的工作解决方案代码。

这是应该启动许多进程的类

package startothermain;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Starter {

    public static void main(String[] args) {
        int starts = 4;

        for (int i = 0; i < starts; ++i) {
            System.out.println("Starting an app");
            ProcessBuilder pb = new ProcessBuilder("java.exe", "-cp", "bin", "Started", "arg0");
            try {
                pb.start();
            } catch (IOException ex) {
                Logger.getLogger(Starter.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

这是应该启动并显示GUI的类

package startothermain;

import javax.swing.JOptionPane;

public class Started {

    public static void main(String[] args) {
        JOptionPane.showMessageDialog(null, args[0]);
    }
}

我尝试了在其他答案中找到的ProcessBuilder和Runtime.getRuntime()建议,但它们似乎不起作用。我总是得到某种“未找到”的错误,比如这个

SEVERE: null
java.io.IOException: Cannot run program "java.exe": error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1041)
    at startothermain.Starter.main(Starter.java:35)
Caused by: java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.<init>(UNIXProcess.java:135)

我正在使用NetBeans并单击“运行”按钮,因此.java文件应该正确编译并位于同一文件夹中。我希望这对IDE创建的src / build文件夹没有任何问题。

编辑:我试图找到java.exe,但我在Linux上。叹。我改为“java”,但我仍然有同样的问题。应设置路径变量。而且,我担心,如果我给它一个完整的路径,它将变得不可移植。

尝试在Linux上获取JAVA_HOME

System.getenv("JAVA_HOME"); // returns null
System.getProperty("java.home"); // returns /usr/lib/jvm/java-7-openjdk-amd64/jre

在Windows上

System.getenv("JAVA_HOME"); // returns C:\Program Files\Java\jdk1.7.0_51
System.getProperty("java.home"); // returns C:\Program Files\Java\jdk1.7.0_51\jre

EDIT2:这个新代码不会产生错误,但也不会打开任何GUI。我在Windows和Linux上都试过这个,结果相同。

String javaHome = System.getProperty("java.home");
ProcessBuilder pb = new ProcessBuilder(javaHome + "/bin/java", "-cp", "bin", "Started", "arg0");

EDIT3:我重定向了错误并输出了流程构建器的流(而不是创建过程),结果发现Java ClassLoader找不到类。我想问题不是JAVA_HOME,而是路径问题。

这是新代码

package startothermain;

import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Starter {

    public static void main(String[] args) {
        int starts = 4;
        System.out.println(System.getProperty("java.home")); // prints C:\Program Files\Java\jdk1.7.0_51\jre
        System.out.println(System.getenv("JAVA_HOME")); // prints C:\Program Files\Java\jdk1.7.0_51

        System.out.println("Working Directory = "
                + System.getProperty("user.dir")); // prints C:\Users\Agostino\Documents\NetBeansProjects\StartOtherMain

        for (int i = 0; i < starts; ++i) {
            System.out.println("Starting an app");
            ProcessBuilder pb = new ProcessBuilder("java", "build.classes.startothermain.Started");
            File log = new File("log");
            pb.redirectOutput(log);
            pb.redirectError(log);
            try {
                pb.start();
            } catch (IOException ex) {
                Logger.getLogger(Starter.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

在日志文件中,我发现此错误

java.lang.NoClassDefFoundError: build/classes/startothermain/Started (wrong name: startothermain/Started)
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)
Exception in thread "main" 

EDIT4:现在代码有效,但是如果我尝试在Started类中使用.jar库,则无法找到它。

请参阅此Started类,该类使用通过NetBeans添加到项目库的.jar lib(JavaTuples)

package startothermain;

import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Starter {

    public static void main(String[] args) {
        int starts = 1;

        for (int i = 0; i < starts; ++i) {
            System.out.println("Starting an app");
            ProcessBuilder pb = new ProcessBuilder();

            String fullClassName = Started.class.getName();
            pb.command("java", "-cp", "./build/classes", fullClassName, "myArg");

            File log = new File("log");
            pb.redirectOutput(log);
            pb.redirectError(log);
            try {
                pb.start();
            } catch (IOException ex) {
                Logger.getLogger(Starter.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

修复了入门课程

package startothermain;

import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Starter {

    public static void main(String[] args) {
        int starts = 1;

        for (int i = 0; i < starts; ++i) {
            System.out.println("Starting an app");
            ProcessBuilder pb = new ProcessBuilder();

            String fullClassName = Started.class.getName();
            pb.command("java", "-cp", "./build/classes", fullClassName, "myArg");

            File log = new File("log");
            pb.redirectOutput(log);
            pb.redirectError(log);
            try {
                pb.start();
            } catch (IOException ex) {
                Logger.getLogger(Starter.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

ProcessBuilder日志中的错误

Exception in thread "main" java.lang.NoClassDefFoundError: org/javatuples/Pair
    at startothermain.Started.main(Started.java:28)
Caused by: java.lang.ClassNotFoundException: org.javatuples.Pair
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    ... 1 more

EDIT5:工作代码

入门课程

package startothermain;

import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Starter {

    public static void main(String[] args) {
        int starts = 1;

        for (int i = 0; i < starts; ++i) {
            System.out.println("Starting an app");
            ProcessBuilder pb = new ProcessBuilder();

            String fullClassName = Started.class.getName();
            String pathToClassFiles = new File("./build/classes").getPath();
            String pathSeparator = File.pathSeparator; // ":" on Linux, ";" on Windows
            String pathToLib = new File("./lib/javatuples-1.2.jar").getPath();
            pb.command("java", "-cp", pathToLib + pathSeparator + pathToClassFiles, fullClassName, "myArg");

            File log = new File("log" + i + ".txt"); //debug log for started process
            try {
                pb.redirectOutput(log);
                pb.redirectError(log);
                pb.start();
            } catch (IOException ex) {
                Logger.getLogger(Starter.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

开始上课

package startothermain;

import javax.swing.JOptionPane;
import org.javatuples.Pair;

public class Started {

    public static void main(String[] args) {
        Pair<String, Integer> pair = Pair.with("One", 1);
        JOptionPane.showMessageDialog(null, args[0] + " " + pair);
    }
}

2 个答案:

答案 0 :(得分:2)

根据您的要求,我在答案中总结了我的意见。

您的第一个问题是您尝试在Linux或Mac机上调用java.exe,但这并不符合将文件类型包含在名称中的Microsoft惯例。因此,Linux和Mac通常使用java

可执行文件的路径也可能因计算机而异。因此,可能最通用的方法是使用JAVA_HOME环境变量来定位java可执行文件,该变量可以通过System.getenv("JAVA_HOME");System.getProperty("java.home");通过Java获取。但请注意,它们可能不会明确指向所需的目录。特别是一些Linux发行版将所有二进制文件放在/bin/usr/bin内,因此${JAVA_HOME}/bin/java可能不可用。在这种情况下,您应该创建一个指向可执行文件的(硬)链接。

如果未设置路径,您可以在正在执行应用程序的控制台会话中手动设置它(在Linux set JAVA_HOME=C:\Program Files\Java上的Windows export JAVA_HOME=/opt/java(或新版Windows上的setx))。这也可以使用user-priviledges

完成

在处理流程时,强烈建议take care of in- and output-streams。链接的文章深入解释了为什么要处理它 - 不仅要捕获被调用进程抛出的异常。

在调用进程(特别是Java可执行文件)时,您有几个选择: 您可以使用new ProcessBuilder("java", "-cp", "path/to/your/binaries", "package.ClassName");直接调用Java进程(假设Java在您的PATH上),也可以通过shell调用Java可执行文件 - 在Linux上。你也可以使用new ProcessBuilder("/bin/bash", "-c", "java -cp path/to/your/binaries package.ClassName");(虽然引物明显更好)。

在动态加载类/库时,您必须使用完全限定的类名。因此,如果您在项目的根目录中调用Java流程,并且您的构建工具在./build/classes内生成类文件,而您的类Test位于包testpackage中您将得到以下集合:./build/classes/testpackage/Test.class。要启动一个调用Test.class中包含的main方法的新Java进程,必须使用以下命令:java -cp ./build/classes testpackage.Test否则Java将无法找到Test的类定义和执行main方法。

必须将缺少的依赖项添加到调用Java命令的类路径(-cp ...)段中。 F.e:java -cp lib/jar1.jar;lib/jar2.jar;build/classes/* package.ClassName。多个归档或目录由;分隔,星号*也可以包含目录中的所有内容。

还有一个注意事项:如果您尝试发送“应用程序”,则需要将此代码调整为更通用的版本(属性文件fe),因为路径可能完全不同,因此很可能失败。

如果我忘记了什么,请告诉我。

答案 1 :(得分:0)

你是否尝试从命令提示符运行java.exe,如果它在那里不起作用你需要设置java路径到JAVA安装这可以通过在系统变量中设置变量JAVA_PATH来完成,这应该指向你的Jdk bin文件夹。

如果这不起作用,那么我认为你需要提供JAVA.exe的完整路径,因为程序试图找到这个文件并且它无法找到该文件并且它给出了错误

相反,您可以尝试制作更好的解决方案,因为线程使用的资源更少,效率更高

相关问题