[英]run a executable jar file within java program using class loaders
我聽說你可以使用Process或使用ClassLoaders運行其他java文件。
我有一個可執行jar'test.jar',其主類叫做Test
。
我找到了一種使用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);
}
一些代碼可以幫助您入門,這基本上就是@Felipe所說的。
請記住,這不是完全相同的事情。 你沒有產生一個新的過程,只有一個新的線程; 你可能會面臨巨大的課堂負擔; Test.jar
文件中的System.exit()
類的東西也會導致容器程序終止,依此類推。
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();
基本方法是:
public static void main(String[])
方法,以及 main
方法,傳遞命令的命令行參數。 在這種特殊情況下的問題是設置System.in和System.out流,以便您可以與在同一JVM中運行的“子應用程序”進行通信。 問題是“子應用程序”期望System.out成為它將輸出寫入的流,並且“父應用程序”將從中讀取。 但是“父應用程序”期望System.out成為控制台(或其他)的輸出流。 這是行不通的,因為System.in/out/err是類字段,兩個“應用程序”都不可避免地具有相同的值。
解決方案是將父應用程序類的代碼更改為不使用System.in/out/err字段。 在“父”調用子System.setOut(...)
的main
方法之前,它必須使用System.setOut(...)
將其設置為將寫入緩沖區的自定義輸出流實例。 然后你需要一個匹配的輸入流實例,“父”可以讀取...代替代碼中的bis
。
您需要解決的另一件事是“子”應用程序將調用System.exit()
的可能性。 這會產生令人遺憾的效果,即拔掉父母的插頭。
還有各種其他復雜性,比如清理線程和“孩子”創建的其他東西。 除非你的JVM實現了Isolates JSR(沒有主流的JVM,AFAIK),否則其中一些基本上是無法解決的。
簡而言之,在一般情況下這樣做非常困難,有些事情你根本無法完全正確。 除非您可以消除/避免這些問題,否則實現替代入口點和其他通信方式要簡單得多。
您可以使用java.net.URLClassLoader類。 您必須實例化URLClassLoader,傳遞所需JAR的URL(可以是文件URL)。 然后,您可以使用此類加載器使用main方法加載類。 URLClasLoader.loadClass()方法將返回表示已加載類的Class實例。 有了它,你可以通過reflecton實例化它並進一步調用它。 你必須直接調用main()方法。
此代碼可能對您有所幫助:
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 });
}
}
從這里來 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.