Можно ли динамически выгружать и перезагружать (другие версии того же) JAR? - PullRequest
16 голосов
/ 08 апреля 2009

Я пишу серверную программу, которая используется для запуска модульных тестов API (отображение большого количества информации и предоставление веб-доступа для контроля / контролировать все это) ...

Этот API известен серверу во время компиляции и предоставляется как баночка.

Для возможности сравнения результатов модульного тестирования разных версий API (без перезапуска сервера), Я хочу иметь возможность выгрузить «текущую» версию API, и перезагрузить более новый (или более старый).

Я не хочу использовать URLClassLoader и вызывать каждый метод по имени
(используя getDeclaredMethod("someMethod")),
потому что сервер сильно зависит от API, и это будет сложно «обернуть» каждый вызов метода таким грязным способом.

Я думал: поскольку все интерфейсы всех версий JAR такие же , не могу ли я сделать это путем перезагрузки другой версии JAR (без вызова по имени?).

Примечание. Я использую последние версии Java SE (6) и Java EE (5).

Если вы думаете, что я пытаюсь достичь, невозможно, пожалуйста, предложите «обходной путь» или другую концепцию.

Ответы [ 6 ]

10 голосов
/ 08 апреля 2009

Я думаю, что если вы загрузите класс, используя

Class.forName(clsname, init, classloader); 

( Javadoc здесь) вы получите экземпляр класса, предоставленный данным загрузчиком классов. Все загруженное из-за этого класса также будет загружено через тот же загрузчик классов.

Пока вы очень осторожны с объектами, созданными с этого момента (для учета GC), вы должны иметь возможность перезагрузить разные версии. Я делал это раньше в Java 1.3, потребовалось много отладки, но в конце у меня было приложение «начальной загрузки», которое загрузило класс Runnable по имени и смогло «мягко перезапустить», создав новый загрузчик классов на другой URL и снова.

5 голосов
/ 04 мая 2009

Вы можете программно изменить ваш путь к классу, чтобы отразить ваши изменения 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);

где jarFile - версия файла, который вы хотите использовать / перезаписать.

4 голосов
/ 09 июля 2009

Вы можете использовать пакет с открытым исходным кодом: JclLoader , который помогает в загрузке разных версий одного и того же фляги. Это также было необходимо для тестирования в одной из наших систем.

Ссылка: http://sourceforge.net/projects/jcloader/

1 голос
/ 08 апреля 2009

OSGi - это фреймворк, который позволит вам это сделать. JSR 277 модульная система Java также предназначена для этого (я думаю). Я не следил за дебатами OSGi -vs- JSR 277, поэтому я не знаю, пытаются ли они вообще их испортить.

Вы можете свернуть свои собственные с помощью загрузчиков классов, но это будет менее "весело".

0 голосов
/ 08 апреля 2009

Да. Я видел это на конференции NFJS . Именно такие вещи, как веб-контейнеры, поддерживают горячее развертывание приложений и предполагают использование возможностей загрузчиков классов. Для этого вам нужно создать новый загрузчик классов и использовать его для загрузки рассматриваемой библиотеки ... затем выбросить загрузчик (или нет) и создать другой, когда вы захотите перезагрузить. Возможно, вам также придется переопределить поведение загрузчика классов (я помню кое-что о загрузчиках классов, получающих классы сначала через своих родителей по умолчанию.) Также я помню предупреждение о том, что объекты, созданные различными загрузчиками классов, , а не совместимы (не одного типа) друг с другом, даже если файл .class точно такой же.

Для меня это в основном глубокая магия . ; -)

0 голосов
/ 08 апреля 2009

Наверное, нет. Загрузчик классов Java на самом деле не поддерживает загрузку во время выполнения; даже доступные загрузчики классов - это хаки, использующие прокси-объект.

...