【问题标题】:How to set multiple classpath entries in java at runtime?java - 如何在运行时在java中设置多个类路径条目?
【发布时间】:2016-09-08 06:51:48
【问题描述】:

我想从我当前的 java 项目中执行一个 java 程序。它有多个 jar 依赖项,应该在执行它之前添加到类路径中。首先,我尝试使用普通的 java 命令执行 -

  String classDir = "";
  for (int i = 0; i < compilerConfiguration.getClasspathEntries().size(); i++) {
        classDir = classDir + compilerConfiguration.getClasspathEntries().get(i) + ";";
  }
  runProcess("java -cp " + classDir + " topLevelProject.com.test.project.App");

  private static void runProcess(String command) throws Exception {
    Process pro = Runtime.getRuntime().exec(command);
    printLines(command + " stdout:", pro.getInputStream());
    printLines(command + " stderr:", pro.getErrorStream());
    pro.waitFor();
    System.out.println(command + " exitValue() " + pro.exitValue());
  } 

但是由于有多个类路径条目,它给了我错误 -

  java.io.IOException: Cannot run program "java": CreateProcess error=206, The filename or extension is too long

classDir 的内容有点像这样 -

E:\test\maven\com.test.project\target\classes;C:\Users\dd\.m2\repository\p2\osgi\bundle\com.t.cep.studio.cli\5.3.0.164\com.t.cep.studio.cli-5.3.0.164.jar[+com/t/cep/studio/cli/studiotools/*;?**/*];C:\Users\dd\.m2\repository\p2\osgi\bundle\org.eclipse.core.runtime\3.11.1.v20150903-1804\org.eclipse.core.runtime-3.11.1.v20150903-1804.jar[~org/eclipse/core/internal/preferences/legacy/*;~org/eclipse/core/internal/runtime/*;+org/eclipse/core/runtime/*;?**/*];

另外,我尝试在执行 java 命令之前动态设置类路径:

  try {
        for (int i = 0; i < compilerConfiguration.getClasspathEntries().size(); i++) {
            String filePath = "file://" + compilerConfiguration.getClasspathEntries().get(i);
            URL[] url = { new URL(filePath) };
            ClassLoader currentThreadClassLoader = Thread.currentThread().getContextClassLoader();
            URLClassLoader urlClassLoader = new URLClassLoader(url, currentThreadClassLoader);
            Thread.currentThread().setContextClassLoader(urlClassLoader);
        }
        runProcess("java  topLevelProject.com.test.project.App");
    } catch (Exception e) {
        e.printStackTrace();
    }  

但它没有按预期设置类路径。还有其他解决方法吗?

【问题讨论】:

  • 您的第二种方法实际上并没有在任何地方设置类路径。至于第一个 - 文件的任何路径是否包含空格?
  • no.. 没有空格.. 'compilerConfiguration.getClasspathEntries()' 中有大约 141 个条目。我在第二种方法中遗漏了什么吗?
  • 是的,您错过了命令在单独的 JVM 中运行的事实,因此与当前线程的类加载器无关。您必须传递-cp(或CLASSPATH 环境变量)。你能以某种方式分享classDir中的确切字符串吗?
  • 嗯。它似乎有很多特殊字符。您是否尝试将其放在命令中的双引号内?
  • 你检查过这个问题吗:stackoverflow.com/questions/201816/…

标签: java runtime classpath


【解决方案1】:

除了@Szmeby 的回答,如果你不知道如何使用里面有classpath 的文件,你可以尝试创建一个“pathing jar”。

“Pathing jar”仅包含 Manifest.mf 文件,其中包含下一个条目:

Class-Path: some.jar another.jar others.jar

您还可以使用通配符来减少长度。

【讨论】:

    【解决方案2】:

    我认为这主要是由命令行长度限制引起的操作系统问题,而不是 java 问题。我在玩 jdeps 时遇到了同样的问题,它还需要一个巨大的类路径。最终,我将类路径导出到纯文本文件中,并将该文件内容作为命令参数内联。

    假设包含类路径字符串的文本文件名是:cp.txt

    其内容(部分):

    /home/anon/.m2/repository/com/app/generator/2.0.jar:/home/anon/.m2/repository/com/app/model/2.0.jar:/home/anon/.m2/repository/com/generator-helpers/2.0.jar:/home/anon/.m2/repository/org/eclipse/emf/org.eclipse.emf.ecore/2.10.1-v20140901-1043/org.eclipse.emf.ecore-2.10.1-v20140901-1043.jar:/home/anon/.m2/repository/org/eclipse/emf/org.eclipse.emf.common/2.10.1-v20140901-1043/org.eclipse.emf.common-2.10.1-v20140901-1043.jar:/home/anon/.m2/repository/org/eclipse/emf/org.eclipse.emf.ecore.xmi/2.10.1-v20140901-1043/org.eclipse.emf.ecore.xmi-2.10.1-v20140901-1043.jar:/home/anon/.m2/repository/commons-io/commons-io/2.1/commons-io-2.1.jar:etc...
    

    那么你应该像这样执行你的命令:

    runProcess("java -cp $(< cp.txt) topLevelProject.com.test.project.App");
    

    它可以使用任何大小的类路径字符串,但它是一个仅限linux的解决方案。我不知道如何在 Windows 命令提示符中内联文件内容。好吧,至少我希望它能给你一些继续前进的想法。

    【讨论】:

    • 谢谢你..它帮助我继续前进..因为它是特定于平台的,我在我的项目中使用了 pathing-jar
    【解决方案3】:

    从 Java 启动 Java 应用程序的另一个解决方案是使用类加载器。这具有以下优点:

    • 您可以保证新程序使用与您的程序相同的 Java 版本运行,从而避免多次安装。
    • 如果您愿意,新程序可以更轻松地与您的程序进行通信(尽管如果您选择此路线,则根本不需要这样做)。
    • 它更加独立于平台,因为任何具有奇怪命令行配置的设置都不是问题。

    要使用此解决方案,只需使用 URLClassLoader 加载所有必要的 jar,然后通过反射调用 main 方法:

    URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{
        new URL("file://path/to/jar/1.jar"),
        new URL("file://path/to/jar/2.jar"),
        new URL("file://path/to/jar/3.jar"),
        new URL("file://path/to/jar/4.jar"),
        new URL("file://path/to/jar/5.jar")
    });
    
    Class<?> clazz = urlClassLoader.loadClass("topLevelProject.com.test.project.App");
    clazz.getMethod("main", String[].class).invoke(null, new String[]{"Command", "Line", "Arguments", "Here"});
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多