Вопрос

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

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

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

Это было полезно?

Решение

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

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

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

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

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

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

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

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

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

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

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

Если все сделано правильно, не должно произойти КлассКастИсключение или Ошибка связи и т. д.

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

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

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top