Выгрузка классов на java?


У меня есть пользовательский загрузчик классов, так что настольное приложение может динамически запускать загрузку классов с сервера приложений, с которым мне нужно поговорить. Мы сделали это, так как количество банок, которые требуются для этого, смешно (если бы мы хотели отправить их). У нас также есть проблемы с версиями, если мы не загружаем классы динамически во время выполнения из библиотеки AppServer.

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

надеюсь, что это имеет смысл

7 153

7 ответов:

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

одним из возможных решений вашей проблемы является наличие загрузчика классов для каждого файла jar и загрузчика классов для каждого из серверов приложений, который делегирует фактическую загрузку классов конкретным загрузчикам классов Jar. Таким образом, вы можете указать на разные версии файла jar для каждый сервер приложений.

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

Если вы не хотите использовать OSGI, одной из возможных реализаций может быть использование одного экземпляра JarClassloader класс для каждого файла JAR.

и создать новый класс MultiClassloader, который расширяется Загрузчик классов. Этот класс внутренне будет иметь массив (или список) JarClassloaders, а в методе defineClass () будет проходить через все внутренние загрузчики классов, пока не будет найдено определение или не будет создано исключение NoClassDefFoundException. Несколько методов доступа могут быть предоставлены для добавления новых JarClassloaders в класс. Существует несколько возможных реализаций в сети для мультиклассового загрузчика, поэтому вам может даже не понадобиться писать свой собственный.

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

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

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

класс определяется его пакетом, его именем и загрузчиком класса, который он первоначально загрузил. Программа" прокси " загрузчик классов, который является первым, что загружается при запуске JVM. Рабочий процесс:

  • программа запускается, и реальный "главный" - класс загружается этим загрузчиком прокси-классов.
  • каждый класс, который затем обычно загружается (т. е. не через другую реализацию загрузчика классов, которая может нарушить иерархию), будет делегирован этому загрузчику классов.
  • делегаты загрузчика прокси-классов java.x и sun.x в системный загрузчик классов (эти не должен быть загружены через любой другой classloader чем системный classloader).
  • для каждого заменяемого класса создайте экземпляр classloader (который действительно загружает класс и не делегирует его родительскому classloader) и загрузите его через это.
  • хранить пакет / имя классов как ключи и загрузчик классов как значения в структуре данных (т. е. Hashmap).
  • каждый раз, когда прокси-загрузчика получает запрос для класса, который был загружен ранее, он возвращает класс из класса загрузчик хранился раньше.
  • этого должно быть достаточно, чтобы найти массив байтов класса вашим загрузчиком классов (или "удалить" пару ключ/значение из вашей структуры данных) и перезагрузить класс в случае, если вы хотите его изменить.

сделано правильно там не должно прийти ClassCastException или LinkageError etc.

для получения дополнительной информации об иерархии загрузчика классов (да, это именно то, что вы реализуете здесь ;- ) смотреть в "серверное программирование на Java" Теда Ньюарда - эта книга помогла мне реализуя нечто очень похожее на то, что вы хотите.

Я написал пользовательский загрузчик классов, из которого можно выгружать отдельные классы без GCing загрузчика классов. Jar Class Loader

загрузчики классов могут быть сложной проблемой. Вы можете особенно столкнуться с проблемами, если вы используете несколько загрузчиков классов и не имеете их взаимодействия четко и строго определены. Я думаю, что для того, чтобы на самом деле иметь возможность выгружать класс youlre going go нужно удалить все ссылки на любые классы(и их экземпляры), которые вы пытаетесь выгрузить.

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

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

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

классы имеют неявную сильную ссылку на их экземпляр ClassLoader, и наоборот. Они мусора, как с объектами Java. Без нажатия на интерфейс инструментов или аналогичный, вы не можете удалить отдельные классы.

Как всегда, вы можете получить утечку памяти. Любая сильная ссылка на один из ваших классов или загрузчик классов приведет к утечке всего этого. Это происходит с реализациями Sun ThreadLocal, java.язык SQL.DriverManager и java.бобы, например.

Если вы смотрите в прямом эфире, если выгрузка класс работал в JConsole или что-то еще, попробуйте также добавить java.lang.System.gc() в конце вашего класса разгрузочные логики. Он явно запускает сборщик мусора.