目標是讓一個簡單的Java類啓動一個jar main-class。當主要類完成時,可以詢問是否要重新加載。通過這種方法,它可以自行更新並重新運行。小班允許一個java程序自動更新自己
啓動器是通過URLClassloader加載jar,然後卸載/重新加載更改後的jar。該jar可以通過對Launcher的修改或通過調用提供的dos/unix腳本來更改,該腳本將新jar替換爲舊jar的位置。
整個程序如下。經過測試,它似乎工作順利。
java Launcher -jar [path_to_jar] -run [yourbatchfile] [-runonce]?可選]
1)啓動程序在你的jar文件中查找「Main-Class」屬性,這樣它就不需要給實際的類運行。
2)將調用公共靜態無效的主要(字串[] args)「,並通過它,你提供的命令行
3)當你的程序完成後,啓動程序將調用在剩餘的參數你程序方法'公共靜態布爾reload()',如果結果是'真',這將觸發重新加載。
4)如果您指定了-runonce,那麼程序將不會重新加載。 5)如果指定了-run [batchfile],那麼批處理文件將在重新加載之前運行。
我希望這對一些人有幫助。
快樂編碼!
import java.io.File;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
public class Launcher {
public static void main(String[] args) {
new Launcher().run(new ArrayList<>(Arrays.asList(args)));
}
private void run(List<String> list) {
final String jar = removeArgPairOrNull("-jar", list);
final boolean runonce = removeArgSingle("-runonce", list);
final String batchfile = removeArgPairOrNull("-run", list);
if (jar == null) {
System.out.println("Please add -jar [jarfile]");
System.out.println("All other arguments will be passed to the jar main class.");
System.out.println("To prevent reloading, add the argument to -runonce");
System.out.println("To provide another program that runs before a reload, add -run [file]");
}
boolean reload;
do {
reload = launch(list.toArray(new String[0]), new String(jar), new String(batchfile), new Boolean(runonce));
System.out.println("Launcher: reload is: " + reload);
gc();
if (reload && batchfile != null) {
try {
System.err.println("Launcher: will attempt to reload jar: " + jar);
runBatchFile(batchfile);
} catch (IOException | InterruptedException ex) {
ex.printStackTrace(System.err);
System.err.println("Launcher: reload batchfile had exception:" + ex);
reload = false;
}
}
} while (reload);
}
private boolean launch(String[] args, String jar, String batchfile, boolean runonce) {
Class<?> clazz = null;
URLClassLoader urlClassLoader = null;
boolean reload = false;
try {
urlClassLoader = new URLClassLoader(new URL[]{new File(jar).toURI().toURL()});
String mainClass = findMainClass(urlClassLoader);
clazz = Class.forName(mainClass, true, urlClassLoader);
Method main = clazz.getMethod("main", String[].class);
System.err.println("Launcher: have method: " + main);
Method reloadMethod;
if (runonce) {
// invoke main method using reflection.
main.invoke(null, (Object) args);
} else {
// find main and reload methods and invoke using reflection.
reloadMethod = clazz.getMethod("reload");
main.invoke(null, (Object) args);
System.err.println("Launcher: invoked: " + main);
reload = (Boolean) reloadMethod.invoke(null, new Object[0]);
}
} catch (final Exception ex) {
ex.printStackTrace(System.err);
System.err.println("Launcher: can not launch and reload this class:" + ex);
System.err.println("> " + clazz);
reload = false;
} finally {
if (urlClassLoader != null) {
try {
urlClassLoader.close();
} catch (IOException ex) {
ex.printStackTrace(System.err);
System.err.println("Launcher: error closing classloader: " + ex);
}
}
}
return reload ? true : false;
}
private static String findMainClass(URLClassLoader urlClassLoader) throws IOException {
URL url = urlClassLoader.findResource("META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(url.openStream());
Attributes attr = manifest.getMainAttributes();
return attr.getValue("Main-Class");
}
private static void runBatchFile(String batchfile) throws IOException, InterruptedException {
System.out.println("Launcher: executng batchfile: " + batchfile);
ProcessBuilder pb = new ProcessBuilder("cmd", "/C", batchfile);
pb.redirectErrorStream(true);
pb.redirectInput(Redirect.INHERIT);
pb.redirectOutput(Redirect.INHERIT);
Process p = pb.start();
p.waitFor();
}
private static String removeArgPairOrNull(String arg, List<String> list) {
if (list.contains(arg)) {
int index = list.indexOf(arg);
list.remove(index);
return list.remove(index);
}
return null;
}
private static boolean removeArgSingle(String arg, List<String> list) {
if (list.contains(arg)) {
list.remove(list.indexOf(arg));
return true;
}
return false;
}
private void gc() {
for (int i = 0; i < 10; i++) {
byte[] bytes = new byte[1024];
Arrays.fill(bytes, (byte) 1);
bytes = null;
System.gc();
System.runFinalization();
}
}
}
哪些代碼抱怨清單?確切的錯誤信息是什麼樣的? findMainClass是做什麼的? – MvG
findMainClass只是查看jar清單來查找主類。 我會重新發布整個程序。 –
在urlclassloader重新加載消息,它找不到方法(No SuchMethod)之後失敗:clazz.getMethod(「reload」) 也許你可以嘗試它並查看錯誤的位置,或者這可能是一些限制處理和重新加載urlclassloader?/ –