java 在运行时动态加载 jar?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27187566/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Load jar dynamically at runtime?
提问by JoelP
My current java project is using methods and variables from another project (same package). Right now the other project's jar has to be in the classpath to work correctly. My problem here is that the name of the jar can and will change because of increasing versions, and because you cannot use wildcards in the manifest classpath, it's impossible to add it to the classpath. So currently the only option of starting my application is using the -cp
argument from the command line, manually adding the other jar my project depends on.
我当前的 java 项目正在使用另一个项目(同一个包)中的方法和变量。现在另一个项目的 jar 必须在类路径中才能正常工作。我的问题是 jar 的名称可以并且会随着版本的增加而改变,并且因为您不能在清单类路径中使用通配符,所以不可能将它添加到类路径中。因此,目前启动我的应用程序的唯一选择是使用-cp
命令行中的参数,手动添加我的项目所依赖的另一个 jar。
To improve this, I wanted to load the jar dynamically and read about using the ClassLoader. I read a lot of examples for it, however I still don't understand how to use it in my case.
为了改进这一点,我想动态加载 jar 并阅读有关使用 ClassLoader 的信息。我阅读了很多例子,但是我仍然不明白如何在我的情况下使用它。
What I want is it to load a jar file, lets say, myDependency-2.4.1-SNAPSHOT.jar
, but it should be able to just search for a jar file starting with myDependency-
because as I already said the version number can change at anytime. Then I should just be able to use it's methods and variables in my Code just like I do now (like ClassInMyDependency.exampleMethod()
).
我想要的是加载一个 jar 文件,比如说,,myDependency-2.4.1-SNAPSHOT.jar
但它应该能够只搜索一个以 开头的 jar 文件,myDependency-
因为正如我已经说过的,版本号可以随时更改。然后我应该能够像现在一样(如ClassInMyDependency.exampleMethod()
)在我的代码中使用它的方法和变量。
Can anyone help me with this, as I've been searching the web for a few hours now and still don't get how to use the ClassLoader to do what I just explained.
任何人都可以帮助我解决这个问题,因为我已经在网上搜索了几个小时,但仍然不知道如何使用 ClassLoader 来完成我刚刚解释的事情。
Many thanks in advance
提前谢谢了
回答by Bathsheba
Indeed this is occasionally necessary. This is how I do this in production. It uses reflection to circumvent the encapsulation of addURL
in the system class loader.
事实上,这有时是必要的。这就是我在生产中这样做的方式。它使用反射来规避addURL
系统类加载器中的封装。
/*
* Adds the supplied Java Archive library to java.class.path. This is benign
* if the library is already loaded.
*/
public static synchronized void loadLibrary(java.io.File jar) throws MyException
{
try {
/*We are using reflection here to circumvent encapsulation; addURL is not public*/
java.net.URLClassLoader loader = (java.net.URLClassLoader)ClassLoader.getSystemClassLoader();
java.net.URL url = jar.toURI().toURL();
/*Disallow if already loaded*/
for (java.net.URL it : java.util.Arrays.asList(loader.getURLs())){
if (it.equals(url)){
return;
}
}
java.lang.reflect.Method method = java.net.URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{java.net.URL.class});
method.setAccessible(true); /*promote the method to public access*/
method.invoke(loader, new Object[]{url});
} catch (final java.lang.NoSuchMethodException |
java.lang.IllegalAccessException |
java.net.MalformedURLException |
java.lang.reflect.InvocationTargetException e){
throw new MyException(e);
}
}
回答by B?ng Rikimaru
I needed to load a jar file at runtime for both java 8 and java 9+. Here is the method to do it (using Spring Boot 1.5.2 if it may relate).
我需要在运行时为 java 8 和 java 9+ 加载一个 jar 文件。这是执行此操作的方法(如果可能相关,请使用 Spring Boot 1.5.2)。
public static synchronized void loadLibrary(java.io.File jar) {
try {
java.net.URL url = jar.toURI().toURL();
java.lang.reflect.Method method = java.net.URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{java.net.URL.class});
method.setAccessible(true); /*promote the method to public access*/
method.invoke(Thread.currentThread().getContextClassLoader(), new Object[]{url});
} catch (Exception ex) {
throw new RuntimeException("Cannot load library from jar file '" + jar.getAbsolutePath() + "'. Reason: " + ex.getMessage());
}
}