Java在运行时添加类路径

Java在运行时添加类路径,java,runtime,classpath,Java,Runtime,Classpath,这个问题的答案有很多,在《史塔克溢出》一书中? 但是最常用的方法是将ClassLoader.getSystemClassLoader转换为URLClassLoader,这样就不再有效了 类必须由systemclassloader找到 还有别的解决办法吗? -不重新启动jar -在这种情况下,如果不创建自己的类加载器,我必须用自己的类加载器替换systemclassloader 缺少的类/JAR必须在启动时添加,我不想在带有类路径的清单中添加它们。 我找到了带有premain方法的Java代理。这

这个问题的答案有很多,在《史塔克溢出》一书中? 但是最常用的方法是将ClassLoader.getSystemClassLoader转换为URLClassLoader,这样就不再有效了

类必须由systemclassloader找到

还有别的解决办法吗? -不重新启动jar -在这种情况下,如果不创建自己的类加载器,我必须用自己的类加载器替换systemclassloader

缺少的类/JAR必须在启动时添加,我不想在带有类路径的清单中添加它们。 我找到了带有premain方法的Java代理。这也可以很好地工作,但在本例中,我希望在不调用java-javaagent的情况下启动premain方法:-罐子

目前,我从一开始就重新启动程序,但缺少类路径:

public class LibLoader {
    protected static List<File> files = new LinkedList<>();

    public static void add(File file) {
        files.add(file);
    }

    public static boolean containsLibraries() {
        RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
        String[] classpaths = runtimeMxBean.getClassPath().split(System.getProperty("path.separator"));

        List<File> classpathfiles = new LinkedList<>();
        for(String string : classpaths) classpathfiles.add(new File(string));

        for(File file : files) {
            if(!classpathfiles.contains(file)) return false;
        }

        return true;
    }

    public static String getNewClassPaths() {
        StringBuilder builder = new StringBuilder();

        RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
        builder.append(runtimeMxBean.getClassPath());

        for(File file : files) {
            if(builder.length() > 0) builder.append(System.getProperty("path.separator"));

            builder.append(file.getAbsolutePath());
        }

        return builder.toString();
    }

    public static boolean restartWithLibrary(Class<?> main, String[] args) throws IOException {
        if(containsLibraries()) return false;

        List<String> runc = new LinkedList<>();

        runc.add(System.getProperty("java.home") + "\\bin\\javaw.exe");

        RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
        List<String> arguments = runtimeMxBean.getInputArguments();
        runc.addAll(arguments);

        File me = new File(LibLoader.class.getProtectionDomain().getCodeSource().getLocation().getPath());

        String classpaths = getNewClassPaths();
        if(!classpaths.isEmpty()) {
            runc.add("-cp");
            runc.add(classpaths);
        }

        if(me.isFile()) {
            runc.add("-jar");
            runc.add(me.getAbsolutePath().replace("%20", " "));
        } else {
            runc.add(main.getName());
        }

        for(String arg : args) runc.add(arg);

        ProcessBuilder processBuilder = new ProcessBuilder(runc);
        processBuilder.directory(new File("."));
        processBuilder.redirectOutput(Redirect.INHERIT);
        processBuilder.redirectError(Redirect.INHERIT);
        processBuilder.redirectInput(Redirect.INHERIT);
        Process process = processBuilder.start();

        try {
            process.waitFor();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return true;
    }
}
希望有人有更好的解决方案


问题是,这些类必须在我的系统类加载器中找到,而不是由新的类加载器找到

听起来,当前重新启动JVM的解决方案是唯一干净的方法

无法更改系统类加载器,并且不能在运行时向其添加额外的JAR

如果您试图使用反射来扰乱系统类加载器的数据结构,那么它最多只能是不可移植的,并且依赖于版本。在最坏的情况下,它要么容易出错。。。或者被JVM的运行时安全机制阻止

约翰内斯·库恩在评论中提出的解决方案行不通。JVM引导过程中会参考java.system.class.loader属性。在应用程序运行时,对其进行更改将不会产生任何效果。我不相信他的方法也会奏效

这里有一个可能的替代方法来处理这个问题。。。如果你能尽早找到丢失的罐子

编写一个执行以下操作的启动器类:

保存命令行参数 查找应用程序JAR文件 从MANIFEST.MF中提取主类和类路径属性。 根据以上内容计算出真正的类路径应该是什么。。。以及其他特定于应用程序的逻辑。 使用正确的类路径创建一个新的URLClassLoader,并将系统类加载器作为其父类。 使用它来加载主类。 使用反射查找main方法中的main类。 通过save命令行参数调用它。
这本质上是Spring Bootstrap和OneJar以及其他处理jar中的jar问题的方法,等等。它避免启动2个虚拟机。

这里有什么问题?你有什么错误?目前我没有收到任何错误。但是我想在运行时添加类路径,而不重新启动jar。要将systemclassloader强制转换为urlclassloader并添加URL不再工作,请创建一个新的classloader?问题是,这些类必须在systemclassloader中找到,而不是由新的classloader找到。所以我必须用我自己的来替换systemclassloader,我认为这不起作用。。。这显然是错误的。你有没有读过我的评论,并点击了链接?在过去的一周里,我确实更改了系统类加载器Java14,对于我的案例来说,它确实工作得很好。但是在JVM运行时,您没有这样做!这就是OP想要做的。是的,改变一辆正在行驶的汽车的轮子几乎是不可能的。F1仍然让赛车停下来做这件事。但是我不明白为什么你不想用正确的参数重新启动你的虚拟机一次,以便以后能够进行一些调整。这就是我回答的第一行所说的!是的,我读过你的评论和链接,除非你建议他写一个自定义的加载器来替换系统类加载器,它允许你动态更新类路径,否则这种方法在这里是行不通的。这对运行时类型的安全性有一些可怕的影响。在我看来,最好的解决方案是使用权限参数重新启动VM。感谢您的帮助: