【问题标题】:Is it possible to load different versions of the same DLL in Java?是否可以在 Java 中加载同一个 DLL 的不同版本?
【发布时间】:2010-09-09 16:11:52
【问题描述】:

我有一个与一组第三方库交互的 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?

【问题讨论】:

    标签: java java-native-interface


    【解决方案1】:

    这是可能的,事实上它得到了完全的支持并且效果很好。

    我不得不在生产环境中执行此操作,而在 sun JVM 上它是坚如磐石的。

    基本上,如果您从不同的类加载器加载库,那么它将加载该库的不同副本。就这么简单。

    除非你真的必须这样做,否则我不建议这样做......但它确实有效。

    作为替代方案,根据您的具体要求,您可以让它脱离进程,并在客户端和不同服务器之间建立一个简单的协议(例如使用 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();
    
        }
    }
    

    那种东西.....

    【讨论】:

      【解决方案2】:

      我不知道如何在 Windows 中加载 DLL 的详细信息,但我的直觉告诉我,同时加载重叠的库肯定是不安全的。但也许如果你先卸载第一个,它可能是。

      据我所知,没有办法显式卸载库。如果您查看 java.lang.Classloader.NativeLibrary,您会看到当导致加载它的类加载器被垃圾收集(在其 finalize() 方法中)时,该库被卸载。因此,如果您将它加载到一个单独的类加载器中,然后等待它被垃圾收集(对 System.gc() 进行一些恶意调用以使其更快地发生),然后再加载新的类加载器,这可能会有所帮助。

      【讨论】:

        【解决方案3】:

        这是不安全的,而且实施起来很麻烦。对于不同版本的 dll,可以有不同的类加载器。您必须确保对类加载器进行垃圾收集,以确保 dll 已被卸载。 (见Java JNI - DLL Unloading

        过去,我们通过编写一个轻量级的 java 中介进程来解决这个问题,该进程处理用户的请求并使用请求的 dll 版本创建一个新的子 java 进程。当用户请求一个不同的版本时,中介器会关闭现有的子节点并使用不同的库路径生成一个新的子节点。这种方法效果很好。唯一的缺点是启动新 JVM 所花费的时间,但只有当您非常频繁地收到许多版本切换请求时才会注意到这一点。

        【讨论】:

          猜你喜欢
          • 2011-05-22
          • 1970-01-01
          • 1970-01-01
          • 2011-06-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-06-27
          相关资源
          最近更新 更多