Java 我可以动态卸载和重新加载(相同的其他版本)JAR 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/728140/
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
Can I dynamically unload and reload (other versions of the same) JAR?
提问by ivan_ivanovich_ivanoff
I am writing a server program which is used to run unit tests of an API (displaying lots of information and providing web access to control / monitor the whole thing)...
我正在编写一个服务器程序,用于运行 API 的单元测试 (显示大量信息并提供 Web 访问以控制/监视整个事情)...
This API is known to the server during compile timeand is provided as a JAR.
该 API在编译时为服务器所知,并作为 JAR 提供。
To be able to compare between unit test results of different versionsof the API (without restarting the server), I want to be able to unload the 'current' version of the API, and to reload a newer one (or an older one).
为了能够比较不同版本API 的单元测试结果(无需重新启动服务器),我希望能够卸载 API 的“当前”版本,并重新加载较新的(或较旧的) .
I don't want to use URLClassLoader and invoke every single
method by name
( using getDeclaredMethod("someMethod")
),
because the server heavily depends on the API and it would be
complicated to 'wrap' every method call in such dirty way.
我不想使用 URLClassLoader 并按名称
( using getDeclaredMethod("someMethod")
)调用每个方法,
因为服务器严重依赖 API,并且以这种肮脏的方式“包装”每个方法调用会很复杂。
I was thinking: Since all interfaces of allversions of the JAR are same, couldn't I do it by somehow reloading an other version of the JAR (without that by-name-invokation?).
我在想:既然所有接口全部的JAR的版本是相同的,我不能用某种方式重新加载JAR的其他版本做到这一点(不通过名称管理invokation?)。
Note: I am using latest Java SE (6) and Java EE (5).
注意:我使用的是最新的 Java SE (6) 和 Java EE (5)。
If you think, what I'm trying to achieve is not possible, please suggest a 'workaround' or a different concept.
如果您认为我想要实现的目标是不可能的,请提出“解决方法”或不同的概念。
采纳答案by Steve Reed
I think if you load a class using
我想如果你加载一个类使用
Class.forName(clsname, init, classloader);
(Javadochere) you will get an instance of the class provided by the given classloader. Everything loaded because of that class will also be loaded via the same classloader.
(此处为Javadoc)您将获得给定类加载器提供的类的实例。由于该类加载的所有内容也将通过相同的类加载器加载。
As long as you're very careful with the objects instantiated from this point on (to allow for GC), you should be able to reload different versions. I did this once before with Java 1.3, it took a lot of debugging, but at the end I had a "bootstrap" application that loaded a Runnable
class by name and was able to "soft-restart" by instantiating a new classloader against a different URL and going again.
只要您非常小心地处理从这一点开始实例化的对象(以允许 GC),您就应该能够重新加载不同的版本。我之前用 Java 1.3 做过一次,这需要大量调试,但最后我有一个“引导”应用程序,它Runnable
按名称加载一个类,并且能够通过针对不同的类加载器实例化一个新的类加载器来“软重启” URL,然后再去。
回答by Don Werve
Probably not. The Java classloader doesn't really support run-time loading; even the available classloaders are hacks that use a proxy object.
可能不是。Java 类加载器并不真正支持运行时加载;甚至可用的类加载器都是使用代理对象的黑客。
回答by TofuBeer
OSGiis a framework that will allow you to do it. JSR 277 the Java Module Systemis designed for doing that as well (I think). I have not followed the OSGi -vs- JSR 277 debate, so I don't know f they are trying to marge them at all.
OSGi是一个框架,可以让您做到这一点。 JSR 277 Java 模块系统也是为这样做而设计的(我认为)。我没有关注 OSGi -vs- JSR 277 的辩论,所以我不知道他们是否正在尝试对它们进行调整。
You can roll your own with class loaders, but it'll be less "fun".
您可以使用类加载器自行推出,但它会不那么“有趣”。
回答by Chris Nava
Yes. I've seen it done at a NFJSconference. It's how things like web containers support hot deployment of applications and involves taking advantage of the scope of class loaders. In order to accomplish it you need to create a new class loader and use that to load the library in question.. then throw the loader away (or not) and create another when you want to reload. You may also have to override the behaviour of the class loader (I remember something about class loaders getting classes via their parent first by default.) Also, I remember a warning that objects created by different class loaders are notcompatible (not of the same type) with each other even if the .class file is exactly the same.
是的。我在NFJS会议上看到过它。这就是 Web 容器之类的东西如何支持应用程序的热部署,并涉及利用类加载器的范围。为了完成它,您需要创建一个新的类加载器并使用它来加载有问题的库..然后将加载器扔掉(或不扔掉)并在您想要重新加载时创建另一个。您可能还必须覆盖类加载器的行为(我记得默认情况下类加载器首先通过其父级获取类。)此外,我还记得一个警告,即不同类加载器创建的对象不兼容(不相同类型),即使 .class 文件完全相同。
It's mostly deep magicto me though. ;-)
不过,这对我来说主要是深奥的魔法。;-)
回答by Flueras Bogdan
You could programatically modify your classpath to reflect your JAR changes. Here is how I would do it:
您可以以编程方式修改您的类路径以反映您的 JAR 更改。这是我将如何做到的:
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method m = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
m.setAccessible(true);
m.invoke(urlClassLoader, jarFile.toURI().toURL());
String cp = System.getProperty("java.class.path");
if (cp != null) {
cp += File.pathSeparatorChar + jarFile.getCanonicalPath();
} else {
cp = jarFile.toURI().getPath();
}
System.setProperty("java.class.path", cp);
where jarFileis the version of the jar you want to use/overwrite.
其中jarFile是您要使用/覆盖的 jar 版本。
回答by techzen
You can use the opensource package : JclLoaderwhich helps in loading different versions of the same jar. This was also a need in one of our systems to do testing .
您可以使用开源包:JclLoader,它有助于加载同一 jar 的不同版本。这也是我们的一个系统进行测试的需要。