如何动态地从 jar 文件 运行 java class
How to run a java class from a jar file dynamically
我正在开发一个 java 项目,需要第三方 java 程序 运行ning 作为服务器才能工作。
通常情况下,我会这样做:
java -cp jarfile1.jar:jarfile2.jar className arg1 arg2
然后我会 运行 我的 java 代码。这样就可以了。
我想知道是否有任何方法,包括我的项目所需的两个 .jars,运行 class 直接从我的代码而不是手动启动它.
我已经尝试使用 URLClassLoader
,正如我在一些示例中看到的那样,但要么我做错了,要么 none 涵盖了这个特定的用例。
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{new URL("file:///tmp/jarfile1.jar"),new URL("file:///tmp/jarfile2.jar")});
Class<?> cls = classLoader.loadClass("className");
Method method = cls.getDeclaredMethod ("main");
Object instance = cls.newInstance();
Object result = method.invoke (instance);
产量
Exception in thread "main" java.lang.NoClassDefFoundError: alice/tuprolog/lib/InvalidObjectIdException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2615)
at java.lang.Class.getDeclaredMethod(Class.java:2007)
at pkg1.MainClass.main(MainClass.java:54)
Caused by: java.lang.ClassNotFoundException: alice.tuprolog.lib.InvalidObjectIdException
at java.net.URLClassLoader.run(URLClassLoader.java:366)
at java.net.URLClassLoader.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
... 4 more
请注意,我将 .jars 复制到 /tmp 以隔离失败原因。这些文件存在并且可以访问。
如何在 java 代码中使 运行 成为上面指定的 class?
谢谢!
如果class存在于不同的ClassLoader中,需要使用反射获取:
ClassLoader classLoader = new URLClassLoader(
new URL[] { firstJarURL, secondJarURL });
String[] args = { arg1, arg2 };
try {
Class<?> mainClass = classLoader.loadClass("com.somepackage.ClassName");
mainClass.getMethod("main", String[].class).invoke(null, args);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
我终于修好了!完成的事情:
- 我忘了将第二个 jar 添加到项目的 class 路径中(呃!)
- 因为一切都在项目 classpath 上,所以我只是重新使用了当前的 classloader
最终工作代码:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?> cls = classLoader.loadClass("className");
Method method = cls.getDeclaredMethod("main", String[].class);
Object instance = cls.newInstance();
Object result = method.invoke(null, (Object)args);
感谢大家,特别感谢 VGR 和 Joop Eggen 在评论中指出第二个 jar 的错误!
编辑:正如 JB Nizet 在评论中指出的那样,直接调用 class 的 main() 方法更简单:
className.main(args);
大功告成
我正在开发一个 java 项目,需要第三方 java 程序 运行ning 作为服务器才能工作。
通常情况下,我会这样做:
java -cp jarfile1.jar:jarfile2.jar className arg1 arg2
然后我会 运行 我的 java 代码。这样就可以了。
我想知道是否有任何方法,包括我的项目所需的两个 .jars,运行 class 直接从我的代码而不是手动启动它.
我已经尝试使用 URLClassLoader
,正如我在一些示例中看到的那样,但要么我做错了,要么 none 涵盖了这个特定的用例。
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{new URL("file:///tmp/jarfile1.jar"),new URL("file:///tmp/jarfile2.jar")});
Class<?> cls = classLoader.loadClass("className");
Method method = cls.getDeclaredMethod ("main");
Object instance = cls.newInstance();
Object result = method.invoke (instance);
产量
Exception in thread "main" java.lang.NoClassDefFoundError: alice/tuprolog/lib/InvalidObjectIdException
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2615)
at java.lang.Class.getDeclaredMethod(Class.java:2007)
at pkg1.MainClass.main(MainClass.java:54)
Caused by: java.lang.ClassNotFoundException: alice.tuprolog.lib.InvalidObjectIdException
at java.net.URLClassLoader.run(URLClassLoader.java:366)
at java.net.URLClassLoader.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
... 4 more
请注意,我将 .jars 复制到 /tmp 以隔离失败原因。这些文件存在并且可以访问。
如何在 java 代码中使 运行 成为上面指定的 class?
谢谢!
如果class存在于不同的ClassLoader中,需要使用反射获取:
ClassLoader classLoader = new URLClassLoader(
new URL[] { firstJarURL, secondJarURL });
String[] args = { arg1, arg2 };
try {
Class<?> mainClass = classLoader.loadClass("com.somepackage.ClassName");
mainClass.getMethod("main", String[].class).invoke(null, args);
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
我终于修好了!完成的事情:
- 我忘了将第二个 jar 添加到项目的 class 路径中(呃!)
- 因为一切都在项目 classpath 上,所以我只是重新使用了当前的 classloader
最终工作代码:
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Class<?> cls = classLoader.loadClass("className");
Method method = cls.getDeclaredMethod("main", String[].class);
Object instance = cls.newInstance();
Object result = method.invoke(null, (Object)args);
感谢大家,特别感谢 VGR 和 Joop Eggen 在评论中指出第二个 jar 的错误!
编辑:正如 JB Nizet 在评论中指出的那样,直接调用 class 的 main() 方法更简单:
className.main(args);
大功告成