我听说你可以使用Process或使用ClassLoaders来运行其他java文件。
我有一个名为Test
的主类的可执行jar'test.jar'。
我找到了一种使用Process运行的方法。我需要知道如何使用ClassLoaders。
Process p = Runtime.getRuntime().exec("java -jar test.jar");
BufferedInputStream bis = new BufferedInputStream(p.getInputStream());
synchronized (p) {
p.waitFor();
}
int b=0;
while((b=bis.read()) >0){
System.out.print((char)b);
}
答案 0 :(得分:5)
一些代码可以帮助您入门,这基本上就是@Felipe所说的。
请记住,这不是完全相同的事情。你没有产生一个新的过程,只有一个新的线程;你可能会面临巨大的课堂负担; System.exit()
文件中的Test.jar
之类的内容也会导致容器程序终止,依此类推。
File f = new File("Test.jar");
ClassLoader cl = new URLClassLoader(new URL[] { f.toURI().toURL() }, null);
final Class<?> claxx = cl.loadClass("my.package.Test");
final Method main = claxx.getMethod("main", String[].class);
Thread th = new Thread(new Runnable() {
@Override
public void run() {
try {
main.invoke(claxx, new Object[] { new String[] { "Param1", "Param2" } });
} catch (Throwable th) {
// TODO
}
}
});
th.setContextClassLoader(cl);
th.start();
th.join();
答案 1 :(得分:2)
基本方法是:
public static void main(String[])
方法和main
方法,传递命令的命令行参数。此特定情况下的问题是设置System.in和System.out流,以便您可以与在同一JVM中运行的“子应用程序”进行通信。问题是“子应用程序”期望System.out成为它将输出写入的流,并且“父应用程序”将从中读取。但是“父应用程序”期望System.out成为控制台(或其他)的输出流。这是行不通的,因为System.in/out/err是类字段,两个“应用程序”都不可避免地具有相同的值。
解决方案是将父应用程序类的代码更改为不使用System.in/out/err字段。在“父”调用子进程上的main
方法之前,必须使用System.setOut(...)
将其设置为将写入缓冲区的自定义输出流实例。然后,您需要一个匹配的输入流实例,“父”可以从...中读取...代替代码中的bis
。
您需要解决的另一件事是“子”应用程序可能会调用System.exit()
。这会产生令人遗憾的效果,即拔掉父母的插头。
还有各种其他复杂性,比如清理线程和“孩子”创建的其他东西。除非你的JVM实现了Isolates JSR(没有主流的JVM,AFAIK),否则其中一些基本上是无法解决的。
简而言之,在一般情况下这样做非常困难,有些事情你根本无法完全正确。除非您能够消除/避免这些问题,否则实现替代入口点和其他通信方式要简单得多。
答案 2 :(得分:1)
您可以使用课程java.net.URLClassLoader。 您必须实例化URLClassLoader,传递所需JAR的URL(可以是文件URL)。然后,您可以使用此类加载器使用main方法加载类。 URLClasLoader.loadClass()方法将返回表示已加载类的Class实例。有了它,你可以通过reflecton实例化它并进一步调用它。你必须直接调用main()方法。
答案 3 :(得分:0)
此代码可能对您有所帮助:
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
public class Bootstrap {
public static void main(String[] args) throws Exception {
/*
Assume your application has a "home" directory
with /classes and /lib beneath it, where you can put
loose files and jars.
Thus,
/usr/local/src/APP
/usr/local/src/APP/classes
/usr/local/src/APP/lib
*/
String HOME = "/usr/local/src/YOURAPP";
String CLASSES = HOME + "/classes";
String LIB = HOME + "/lib";
// add the classes dir and each jar in lib to a List of URLs.
List urls = new ArrayList();
urls.add(new File(CLASSES).toURL());
for (File f : new File(LIB).listFiles()) {
urls.add(f.toURL());
}
// feed your URLs to a URLClassLoader!
ClassLoader classloader =
new URLClassLoader(
urls.toArray(new URL[0]),
ClassLoader.getSystemClassLoader().getParent());
// relative to that classloader, find the main class
// you want to bootstrap, which is the first cmd line arg
Class mainClass = classloader.loadClass(args[0]);
Method main = mainClass.getMethod("main",
new Class[]{args.getClass()});
// well-behaved Java packages work relative to the
// context classloader. Others don't (like commons-logging)
Thread.currentThread().setContextClassLoader(classloader);
// you want to prune the first arg because its your main class.
// you want to pass the remaining args as the "real" args to your main
String[] nextArgs = new String[args.length - 1];
System.arraycopy(args, 1, nextArgs, 0, nextArgs.length);
main.invoke(null, new Object[] { nextArgs });
}
}
来自here。