简体   繁体   English

是否可以在Java中加载相同DLL的不同版本?

[英]Is it possible to load different versions of the same DLL in Java?

I have a JNI library that interacts with a set of third party libraries, and there may be more than one version of the third party library on the system. 我有一个与一组第三方库交互的JNI库,系统上可能有多个版本的第三方库。 For each version of the third party library, I have to re-compile the JNI code for comparability reasons. 对于第三方库的每个版本,出于可比性原因,我必须重新编译JNI代码。 Right now I deal with this by loading a DLL with a specific name, and if the version changes I change the names of the JNI interface DLLs so that the correct one for the version has the right name to get loaded. 现在我通过加载具有特定名称的DLL来解决这个问题,如果版本发生更改,我会更改JNI接口DLL的名称,以便正确的版本具有正确的加载名称。

I'd like to be able to dynamically load the dll though, based on which version the user wants to use. 我希望能够根据用户想要使用的版本动态加载dll。 What happens if I call System.loadLibrary twice on DLLs with different names but the same method signatures? 如果我在具有不同名称但具有相同方法签名的DLL上调用System.loadLibrary两次会发生什么?

System.loadLibrary("JNIv1");
// Same code compiled against a different third party version
System.loadLibrary("JNIv2");

I only need to use one of the versions at a time, so it's fine if the old version is no longer accessable. 我只需要一次使用其中一个版本,所以如果旧版本不再可访问就没问题。

Is it possible to load two different versions of a DLL with the same method signatures without re-starting the program? 是否可以使用相同的方法签名加载两个不同版本的DLL而无需重新启动程序?

It is possible and in fact it is totally supported and works brilliantly. 这是可能的,事实上它是完全支持和卓越的工作。

I have had to do this in a production environment and on a sun JVM it is rock solid. 我不得不在生产环境和太阳JVM上做到这一点,它坚如磐石。

Basically, if you load the library from a different classloader, then it will load a different copy of the library. 基本上,如果从其他类加载器加载库,则它将加载库的不同副本。 Its as simple as that. 就这么简单。

I wouldn't recommend doing this unless you really have to... but it does work. 我不建议这样做,除非你真的必须...但它确实有效。

As an alternative, depending on your specific requirements, you could just make it out of process, and have a simple protocol (using say jetty/xstream/httpclient, or netty) between the client and the different servers, each of which has a different dll version loaded. 作为替代方案,根据您的具体要求,您可以将其从流程中删除,并在客户端和不同服务器之间使用简单的协议(使用say jetty / xstream / httpclient或netty),每个服务器都有不同的加载DLL版本。

Essentially this involves you writing a classloader 从本质上讲,这涉及到编写类加载器

public class MyClassLoader extends URLClassLoader {

   protected String findLibrary(String libName) {
         if ( libName.equals("mylib.dll")) {
              return "full/path/to/library";
         }
         else {
              super.findLibrary(libName);
         }
   }
}

Then you arrange to load the implementation of your class using the relevant classloader... 然后你安排使用相关的类加载器加载你的类的实现...

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();

    }
}

That kind of thing..... 那种事.....

I don't know the details of how DLL loading in windows works, but my gut feeling tells me it definitely would not be safe to have overlapping libraries loaded at the same time. 我不知道windows中DLL加载的工作原理,但我的直觉告诉我,同时加载重叠库肯定是不安全的。 But maybe if you first unloaded the first one, it might be. 但也许如果你第一次卸载第一个,它可能是。

As far as I see, there's no way to explicitly unload a library. 据我所知,没有办法显式卸载库。 If you look at java.lang.Classloader.NativeLibrary you'll see that a library is unloaded when the classloader that caused it to be loaded gets garbage collected (in its finalize() method). 如果你看一下java.lang.Classloader.NativeLibrary,你会看到当导致它被加载的类加载器被垃圾收集时(在其finalize()方法中)卸载了一个库。 So if you load it in a separate classloader, and then wait for it to be garbage collected (with some evil calls to System.gc() to make that happen faster) before loading the new one, that might help. 因此,如果你将它加载到一个单独的类加载器中,然后等待它被垃圾收集(带有一些邪恶的调用System.gc()以使这种情况发生得更快),然后再加载新的类加载器,这可能会有所帮助。

This is not safe and is quite messy to implement. 这不安全,实施起来很麻烦。 It is possible to have different classloaders for different versions of the dll. 对于不同版本的dll,可以有不同的类加载器。 You will have to ensure the classloader is garbage collected to be sure that the dll has been unloaded. 您必须确保对类加载器进行垃圾回收以确保已卸载dll。 (See Java JNI - DLL Unloading ) (参见Java JNI - DLL卸载

In the past, we have solved this problem by writing a lightweight java mediator process which handles a user's request and creates a new child java process with the version of the dll requested. 在过去,我们通过编写一个轻量级的java mediator进程来解决这个问题,该进程处理用户的请求并使用所请求的dll版本创建一个新的子java进程。 When a user requests a different version, the mediator shuts down the existing child and spawns a new one with a different library path. 当用户请求不同的版本时,介体会关闭现有的子级并生成具有不同库路径的新子级。 This approach works well. 这种方法效果很好。 The only downside is the time taken to startup new JVMs, but this will only be noticeable if you have many requests for version switches coming in very frequently. 唯一的缺点是启动新JVM所需的时间,但只有当您经常有很多版本交换机请求时才会注意到这一点。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM