Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
允许java程序自动更新自身的小类_Java_Jar_Reload_Urlclassloader_Automatic Updates - Fatal编程技术网

允许java程序自动更新自身的小类

允许java程序自动更新自身的小类,java,jar,reload,urlclassloader,automatic-updates,Java,Jar,Reload,Urlclassloader,Automatic Updates,目标是让一个简单的Java类启动一个jar主类。当主类完成时,可以查询它是否希望重新加载。通过这种方法,它可以自我热更新并重新运行。 启动器通过URLClassloader加载jar,然后卸载/重新加载更改后的jar。可以通过修改Launcher来更改jar,或者通过调用提供的dos/unix脚本来将新jar替换为旧jar 整个程序如下。经过测试,它似乎工作顺利 java启动器-jar[path\u to\u jar]-运行[yourbatchfile][runonce]?可选] 1) Laun

目标是让一个简单的Java类启动一个jar主类。当主类完成时,可以查询它是否希望重新加载。通过这种方法,它可以自我热更新并重新运行。

启动器通过URLClassloader加载jar,然后卸载/重新加载更改后的jar。可以通过修改Launcher来更改jar,或者通过调用提供的dos/unix脚本来将新jar替换为旧jar

整个程序如下。经过测试,它似乎工作顺利

java启动器-jar[path\u to\u jar]-运行[yourbatchfile][runonce]?可选]

1) Launcher在JAR文件中查找“Main Class”属性,这样就不需要为它提供实际的类来运行

2) 它将调用“publicstaticvoidmain(String[]args)”,并将您在命令行中提供的其余参数传递给它

3) 程序完成后,启动器将调用程序方法“publicstaticbooleanload()”,如果结果为“true”,则将触发重新加载

4) 如果指定-runonce,则程序将永远不会重新加载

5) 如果指定了-run[batchfile],则在重新加载之前将运行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();
        }
    }

}
导入java.io.File;
导入java.io.IOException;
导入java.lang.ProcessBuilder.Redirect;
导入java.lang.reflect.Method;
导入java.net.URL;
导入java.net.URLClassLoader;
导入java.util.ArrayList;
导入java.util.array;
导入java.util.List;
导入java.util.concurrent.AtomicBoolean;
导入java.util.jar.Attributes;
导入java.util.jar.Manifest;
公共类启动器{
公共静态void main(字符串[]args){
new Launcher().run(new ArrayList(Arrays.asList(args));
}
专用作废运行(列表){
最后一个字符串jar=removeArgPairOrNull(“-jar”,list);
最终布尔runonce=removeArgSingle(“-runonce”,列表);
最终字符串batchfile=removeArgPairOrNull(“-run”,list);
if(jar==null){
System.out.println(“请添加-jar[jarfile]”);
println(“所有其他参数将被传递到jar主类。”);
System.out.println(“为了防止重新加载,将参数添加到-runonce”);
println(“要提供在重新加载之前运行的另一个程序,请添加-run[file]”);
}
布尔重新加载;
做{
reload=launch(list.toArray(新字符串[0])、新字符串(jar)、新字符串(batchfile)、新布尔值(runonce));
System.out.println(“启动器:重新加载为:“+重新加载”);
gc();
if(重新加载和批处理文件!=null){
试一试{
System.err.println(“启动器:将尝试重新加载jar:+jar”);
runBatchFile(batchfile);
}捕获(IOException | InterruptedException ex){
例如printStackTrace(System.err);
System.err.println(“启动器:重新加载批处理文件有异常:”+ex);
重新加载=错误;
}
}
}同时(重新装载);
}
私有布尔启动(字符串[]参数、字符串jar、字符串批处理文件、布尔运行){
类clazz=null;
URLClassLoader URLClassLoader=null;
布尔重载=假;
试一试{
urlClassLoader=newURLClassLoader(新URL[]{new File(jar).toURI().toURL()});
字符串mainClass=findMainClass(urlClassLoader);
clazz=Class.forName(mainClass,true,urlClassLoader);
方法main=clazz.getMethod(“main”,String[].class);
System.err.println(“启动器:具有方法:“+main”);
方法重新加载法;
如果(跳动){
//使用反射调用main方法。
调用(空,(对象)参数);
}否则{
//查找main和reload方法,并使用反射进行调用。
reloadMethod=clazz.getMethod(“reload”);
调用(空,(对象)参数);
System.err.println(“启动程序:调用:“+main”);
reload=(布尔)reloadMethod.invoke(null,新对象[0]);
}
}捕获(最终异常){
例如printStackTrace(System.err);
System.err.println(“启动器:无法启动并重新加载此类:”+ex);
System.err.println(“>”+clazz);
重新加载=错误;
}最后{
if(urlClassLoader!=null){
试一试{
urlClassLoader.close();
}捕获(IOEX异常){
例如printStackTrace(System.err);
System.err.println(“启动器:关闭类加载器时出错:”+ex);
}
}
}
返回重新加载?真:假;
}
私有静态字符串findMainClass(URLClassLoader URLClassLoader)引发IOException{
URL=urlClassLoader.findResource(“META-INF/MANIFEST.MF”);
清单=新清单(url.openStream());
Attributes attr=manifest.getMainAttributes();
返回属性getValue(“主类”);
}
私有静态void runBatchFile(字符串batchfile)引发IOException、InterruptedException{
System.out.println(“启动器:执行批处理文件:“+batchfile”);
ProcessBuilder pb=新的ProcessBuilder(“cmd”、“/C”、批处理文件);
pb.重定向错误流(真);
pb.redirectInput(Redirect.INHERIT);
pb.redirectOutput(Redirect.INHERIT);
进程p=pb.start();
p、 waitFor();
}
私有静态字符串removeArgPairOrNull(字符串arg,列表){
if(list.contains(arg)){
int index=list.indexOf(arg);
列表。删除(索引);
返回列表。删除(索引);
}
雷图