Можно ли загрузить разные версии одной и той же DLL в Java? - PullRequest
7 голосов
/ 09 сентября 2010

У меня есть библиотека JNI, которая взаимодействует с набором сторонних библиотек, и в системе может быть несколько версий сторонних библиотек. Для каждой версии сторонней библиотеки я должен перекомпилировать код JNI из соображений сопоставимости. Прямо сейчас я имею дело с этим, загружая DLL с определенным именем, и если версия изменяется, я изменяю имена DLL интерфейса JNI так, чтобы правильное имя для версии имело правильное имя для загрузки.

Я хотел бы иметь возможность динамически загружать DLL, в зависимости от того, какую версию пользователь хочет использовать. Что произойдет, если я дважды вызову System.loadLibrary для библиотек DLL с разными именами, но с одинаковыми сигнатурами методов?

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

Мне нужно использовать только одну версию за раз, поэтому хорошо, если старая версия больше недоступна.

Можно ли загрузить две разные версии DLL с одинаковыми сигнатурами методов без перезапуска программы?

Ответы [ 3 ]

3 голосов
/ 10 сентября 2010

Это возможно и фактически полностью поддерживается и прекрасно работает.

Мне приходилось делать это в производственной среде, и на солнечной 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();

    }
}

Такого рода вещи .....

1 голос
/ 09 сентября 2010

Это небезопасно и довольно грязно для реализации.Можно иметь разные загрузчики классов для разных версий DLL.Вы должны будете убедиться, что загрузчик классов собран мусором, чтобы быть уверенным, что dll выгружен.(См. Java JNI - выгрузка DLL )

В прошлом мы решили эту проблему, написав облегченный посреднический процесс Java, который обрабатывает запрос пользователя и создает новый дочерний процесс Java сверсия dll запрашивается.Когда пользователь запрашивает другую версию, посредник выключает существующий дочерний элемент и порождает новый с другим путем к библиотеке.Этот подход работает хорошо.Единственным недостатком является время, затрачиваемое на запуск новых JVM, но это будет заметно только в том случае, если у вас очень много запросов на переключение версий, поступающих очень часто.

1 голос
/ 09 сентября 2010

Я не знаю подробностей о том, как работает загрузка DLL в Windows, но мое интуитивное чувство подсказывает мне, что определенно было бы небезопасно загружать перекрывающиеся библиотеки одновременно.Но, может быть, если вы сначала выгружаете первую, это может быть.

Насколько я вижу, явно выгрузить библиотеку невозможно.Если вы посмотрите на java.lang.Classloader.NativeLibrary, вы увидите, что библиотека выгружается, когда загрузчик классов, который ее вызвал, получает сборщик мусора (в методе finalize ()).Так что, если вы загрузите его в отдельный загрузчик классов, а затем подождите, пока он будет собирать мусор (с некоторыми злыми вызовами System.gc (), чтобы это произошло быстрее), прежде чем загружать новый, это может помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...