如何从单独的jar文件运行jar文件?

时间:2012-03-03 10:20:19

标签: java

  

可能重复:
  Execute another jar in a java program

基本上我想从我正在处理的那个中运行一个外部.jar。

即。我想从bar.jar运行foo.jar

我尝试使用RuntimeProcess来执行“java -jar foo.jar”,但它会打开foo.jar然后立即关闭。有什么提示吗?

3 个答案:

答案 0 :(得分:3)

最简单的解决方案(as Thorn pointed out)将jar作为构建时依赖项并从代码中静态调用它:

ExternalJarMainClass.main(new String[]{"arguments", "to", "main"});

但如果不可能,您可以使用URLClassLoader动态加载jar。如果jar确实可以运行,那么您可以从META-INF/MANIFEST.MF读取主类并通过反射调用main

这是创建单独进程的另一种方法,因为外部代码将在与应用程序相同的进程中运行。也许这是可取的,也许不是 - 这取决于具体情况。

下面是一个(仓促编写和有缺陷的)示例助手类,它就是这样做的。

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class JarRunner {

    private final Method entryPoint;

    public JarRunner(File jarFile) throws
            ClassNotFoundException,
            IOException,
            NoSuchMethodException {
        URL jarUrl = jarFile.toURI().toURL();
        URLClassLoader loader = URLClassLoader.newInstance(
                new URL[]{jarUrl});
        URL manifestUrl = loader.findResource("META-INF/MANIFEST.MF");
        String manifest = resourceToString(manifestUrl);
        Class<?> clazz = loader.loadClass(findMainClassName(manifest));
        entryPoint = clazz.getMethod("main", String[].class);
    }

    public void run(String[] argsToMain) throws
            IllegalAccessException,
            IllegalArgumentException,
            InvocationTargetException {
        entryPoint.invoke(null, (Object) argsToMain);
    }

    private static String resourceToString(URL url) throws IOException {
        InputStream contentStream = url.openStream();
        try {
            BufferedReader r = new BufferedReader(
                    new InputStreamReader(contentStream));
            StringBuilder sb = new StringBuilder();
            String line = null;
            do {
                line = r.readLine();
                if (line != null) {
                    sb.append(line).append('\n');
                }
            } while (line != null);
            return sb.toString();
        } finally {
            contentStream.close();
        }
    }

    private static String findMainClassName(String manifest) {
        Matcher m = MAIN_CLASS_PATTERN.matcher(manifest);
        if (m.find()) {
            return m.group(1);
        }
        return null;
    }

    private static final Pattern MAIN_CLASS_PATTERN = 
            Pattern.compile("Main-Class: (.+)");
}

样本用法:

JarRunner jr = new JarRunner(new File("path/to/MyJar.jar"));
jr.run(new String[]{"arg1", "arg2"});

答案 1 :(得分:2)

你能直接运行foo.jar吗?它是否有主要方法的清单?

我猜你可以。所以你想在像foo.Main

这样的类中启动main方法

选项1:在类路径中包含foo.jar。如果您使用的是IDE,那么这只是将foo.jar添加为库。现在您可以自由地导入包(让我们调用包foo)并从一行Java代码启动第二个java程序: foo.Main.main(NULL); 很可能你想在一个单独的线程中这样做:

class FooRunner extends Thread { 
   public void run() { 
       foo.Main.main(null);
   } 
}

然后你会用这个启动:

FooRunner secondaryApp = new FooRunner();
secondaryApp.start();

选项2 您可以使用类加载器在运行时加载Foo包中的类。 有关java.lang.ClassLoader和this example of a CustomClassLoader

的信息,请参阅Javadocs

答案 2 :(得分:1)

从命令行检查java -jar foo.jar是否正确运行。还要确保路径中有java。在参数中提供java.exe的绝对路径可能更好。

请考虑使用ProcessBuilder代替Runtime