2012-03-03 117 views

回答

3

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

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

检查java -jar foo.jar从命令行运行正确。还要确保java在路径中。在参数中提供到java.exe的绝对路径可能会更好。请使用ProcessBuilder代替Runtime

2

你可以直接运行foo.jar吗?它有一个主要方法的清单吗?

我猜你可以。所以你想要启动一个类的主要方法,如foo.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 您可以在富包加载类在运行时使用类加载器。 见的Javadoc的java.lang.ClassLoader和this example of a CustomClassLoader