[英]Is it possible to load different versions of the same DLL in Java?
我有一个与一组第三方库交互的JNI库,系统上可能有多个版本的第三方库。 对于第三方库的每个版本,出于可比性原因,我必须重新编译JNI代码。 现在我通过加载具有特定名称的DLL来解决这个问题,如果版本发生更改,我会更改JNI接口DLL的名称,以便正确的版本具有正确的加载名称。
我希望能够根据用户想要使用的版本动态加载dll。 如果我在具有不同名称但具有相同方法签名的DLL上调用System.loadLibrary两次会发生什么?
System.loadLibrary("JNIv1");
// Same code compiled against a different third party version
System.loadLibrary("JNIv2");
我只需要一次使用其中一个版本,所以如果旧版本不再可访问就没问题。
是否可以使用相同的方法签名加载两个不同版本的DLL而无需重新启动程序?
这是可能的,事实上它是完全支持和卓越的工作。
我不得不在生产环境和太阳JVM上做到这一点,它坚如磐石。
基本上,如果从其他类加载器加载库,则它将加载库的不同副本。 就这么简单。
我不建议这样做,除非你真的必须...但它确实有效。
作为替代方案,根据您的具体要求,您可以将其从流程中删除,并在客户端和不同服务器之间使用简单的协议(使用say jetty / xstream / httpclient或netty),每个服务器都有不同的加载DLL版本。
从本质上讲,这涉及到编写类加载器
public class MyClassLoader extends URLClassLoader {
protected String findLibrary(String libName) {
if ( libName.equals("mylib.dll")) {
return "full/path/to/library";
}
else {
super.findLibrary(libName);
}
}
}
然后你安排使用相关的类加载器加载你的类的实现...
public interface Implementation {
}
public class ImplementationLookerUpper {
Classloader v1 = new MyClassloader(version1);
Classloader v2 = new MyClassloader(version2);
public Implementation implementationUsingVersion(Version someversion) {
Classloader classloader = pickCorrectClassLoaderForVersion(someVersion);
return (Implementation) classloader.loadClass(RealImplementation.class.getName()).newInstance();
}
}
那种事.....
我不知道windows中DLL加载的工作原理,但我的直觉告诉我,同时加载重叠库肯定是不安全的。 但也许如果你第一次卸载第一个,它可能是。
据我所知,没有办法显式卸载库。 如果你看一下java.lang.Classloader.NativeLibrary,你会看到当导致它被加载的类加载器被垃圾收集时(在其finalize()方法中)卸载了一个库。 因此,如果你将它加载到一个单独的类加载器中,然后等待它被垃圾收集(带有一些邪恶的调用System.gc()以使这种情况发生得更快),然后再加载新的类加载器,这可能会有所帮助。
这不安全,实施起来很麻烦。 对于不同版本的dll,可以有不同的类加载器。 您必须确保对类加载器进行垃圾回收以确保已卸载dll。 (参见Java JNI - DLL卸载 )
在过去,我们通过编写一个轻量级的java mediator进程来解决这个问题,该进程处理用户的请求并使用所请求的dll版本创建一个新的子java进程。 当用户请求不同的版本时,介体会关闭现有的子级并生成具有不同库路径的新子级。 这种方法效果很好。 唯一的缺点是启动新JVM所需的时间,但只有当您经常有很多版本交换机请求时才会注意到这一点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.