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

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

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

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

У вас есть загрузчик классов на каждую банку? Как выполняется архивирование контейнеров OSGI для выгрузки загрузчика классов? Похоже, в классе загрузчика классов нет API выгрузки?

hetaoblog 12.08.2011 12:36
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
180
1
136 226
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

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

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

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

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

Ответ принят как подходящий

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

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

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

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

И создайте новый класс MultiClassloader, расширяющий Classloader. Этот класс внутренне будет иметь массив (или список) загрузчиков JarClass, а в методе defineClass () будет выполняться итерация по всем внутренним загрузчикам классов до тех пор, пока не будет найдено определение или не будет выбрано исключение NoClassDefFoundException. Для добавления новых загрузчиков JarClass в класс может быть предоставлена ​​пара методов доступа. В сети есть несколько возможных реализаций MultiClassLoader, поэтому вам, возможно, даже не потребуется писать свою собственную.

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

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

Также обратите внимание, что согласно java.sun.com/docs/books/jls/second_edition/html/… выгрузка классов является оптимизацией и, в зависимости от реализации JVM, может происходить, а может и не происходить.

user21037 18.02.2010 14:50

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

Ondra Žižka 26.06.2013 22:35

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

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

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

Сделано прямо здесь не должно быть ClassCastException или LinkageError и т. д.

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

Я не понимаю людей, которые отметили -1 для этого ответа, не оставив комментария. На меня смотрится хорошо. Возможно, наличие одного ClassLoader на класс - это слишком много, один ClassLoader на JAR имеет смысл. Можно ли подробнее рассказать о том, как принудительно загрузить класс в предлагаемой схеме? Например. как я могу гарантировать, что экземпляры классов, загруженных ClassLoaderA, не упоминаются экземплярами, загруженными ClassLoaderB?

dma_k 20.01.2011 03:23

@dma_k точно, ответ хороший, но он не касается упомянутых вами ключевых моментов.

zinking 21.10.2013 14:03

@Georgi есть ли существующая реализация, которую мы можем создать / повторно использовать для этого?

Sled 02.08.2017 17:20

Было бы очень полезно, если бы вы могли предоставить образец java-кода. Чтобы быть точным, я ищу, как выгружать классы с помощью CustomClassLoader, но мне не повезло.

Sriharsha g.r.v 13.12.2017 16:59

@ Sriharshag.r.v Вы пробовали это и реализовали образец?

niaomingjian 02.03.2018 04:57

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

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

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

Работает как шарм :). Есть ли способ выгрузить все файлы классов из файла jar?

Ercksen 13.10.2015 14:35

К сожалению, пока нет. Но посмотрим на это. Может быть в будущих выпусках.

Kamran 30.11.2015 20:42

Кстати, я нашел небольшое обходное решение. Если у вас есть один JarClassLoader для каждого загруженного файла jar, вы можете вызвать для него getLoadedClasses(), затем перебрать каждый и выгрузить его.

Ercksen 30.11.2015 20:54

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

Осторожно: System.gc () не обязательно вызывать GC. Он только просит jvm запустить его, но не обеспечивает его выполнение. И IME часто не запускает GC: - \

Juh_ 12.01.2018 11:23

Другие вопросы по теме