У меня есть пользовательский загрузчик классов, чтобы приложение для настольных компьютеров могло динамически начинать загрузку классов с сервера приложений, с которым мне нужно поговорить. Мы сделали это, так как количество банок, необходимых для этого, просто смешно (если мы хотим отправить их). У нас также возникают проблемы с версиями, если мы не загружаем классы динамически во время выполнения из библиотеки AppServer.
Теперь я столкнулся с проблемой, когда мне нужно поговорить с двумя разными AppServer и обнаружил, что в зависимости от того, чьи классы я загружаю первым, я могу плохо сломаться ... Есть ли способ принудительной выгрузки класса без фактического уничтожения JVM?
Надеюсь, это имеет смысл
java
classloader
el_eduardo
источник
источник
Ответы:
Единственный способ, которым Класс может быть выгружен, - это если используемый Classloader является сборщиком мусора. Это означает, что ссылки на каждый отдельный класс и на самого загрузчика классов должны идти по пути додо.
Одним из возможных решений вашей проблемы является наличие Classloader для каждого файла JAR и Classloader для каждого из AppServers, который делегирует фактическую загрузку классов конкретным загрузчикам классов Jar. Таким образом, вы можете указать разные версии файла JAR для каждого сервера приложений.
Это не тривиально, хотя. Платформа OSGi стремится сделать именно это, так как каждый пакет имеет свой загрузчик классов и зависимости определяются платформой. Возможно, хорошим решением было бы взглянуть на это.
Если вы не хотите использовать OSGI, одной из возможных реализаций может быть использование одного экземпляра класса JarClassloader для каждого файла JAR.
И создайте новый класс MultiClassloader, который расширяет Classloader. Этот класс внутренне будет иметь массив (или List) JarClassloaders, а в методе defineClass () будет перебирать все внутренние загрузчики классов до тех пор, пока не будет найдено определение или не будет сгенерировано исключение NoClassDefFoundException. Для добавления новых классов JarClassloaders в класс может быть предоставлена пара методов доступа. Существует несколько возможных реализаций в сети для MultiClassLoader, так что вам может даже не потребоваться написать свою собственную.
Если вы создаете экземпляр MultiClassloader для каждого соединения с сервером, в принципе, возможно, что каждый сервер использует разные версии одного и того же класса.
Я использовал идею MultiClassloader в проекте, где классы, которые содержали пользовательские сценарии, должны были загружаться и выгружаться из памяти, и это работало довольно хорошо.
источник
Да, есть способы загружать классы и «выгружать» их позже. Хитрость заключается в том, чтобы реализовать свой собственный загрузчик классов, который находится между загрузчиком классов высокого уровня (загрузчиком классов System) и загрузчиками классов серверов приложений, и надеяться, что загрузчики классов сервера приложений делегируют загрузку классов верхним загрузчикам. ,
Класс определяется его пакетом, его именем и загрузчиком классов, который он первоначально загрузил. Запрограммируйте загрузчик классов «прокси», который загружается первым при запуске JVM. Процедура:
java.x
иsun.x
системному загрузчику классов (они не должны загружаться через какой-либо другой загрузчик классов, кроме системного загрузчика классов).Сделано прямо там, не должно прийти ClassCastException или LinkageError и т. Д.
Для получения дополнительной информации об иерархиях загрузчиков классов (да, это именно то, что вы реализуете здесь; -) посмотрите на «Серверное программирование на Java» Теда Ньюарда - эта книга помогла мне реализовать нечто очень похожее на то, что вы хотите.
источник
ClassLoader
на класс - это слишком много, одинClassLoader
на JAR имеет смысл. Может быть более конкретно о том, как принудительно загрузить класс в предложенной схеме? Например, как я могу гарантировать, что экземпляры классов, загруженных ClassLoaderA, не ссылаются на экземпляры, загруженные ClassLoaderB?Я написал собственный загрузчик классов, из которого можно выгружать отдельные классы без GCing загрузчика классов. Jar Class Loader
источник
JarClassLoader
файл для каждого загруженного вами jar-файла, вы можете вызватьgetLoadedClasses()
его, затем выполнить итерацию по каждому и выгрузить его.Загрузчики классов могут быть сложной проблемой. Вы можете особенно столкнуться с проблемами, если вы используете несколько загрузчиков классов и не имеете четкого и строго определенного взаимодействия. Я думаю, что для того, чтобы действительно иметь возможность выгрузить класс, который вы собираетесь использовать, необходимо удалить все ссылки на любые классы (и их экземпляры), которые вы пытаетесь выгрузить.
Большинство людей, нуждающихся в подобных вещах, в конечном итоге используют OSGi . OSGi действительно мощный и удивительно легкий и простой в использовании,
источник
Вы можете выгрузить ClassLoader, но вы не можете выгрузить определенные классы. Более конкретно, вы не можете выгружать классы, созданные в ClassLoader, который не находится под вашим контролем.
Если возможно, я предлагаю использовать свой собственный ClassLoader, чтобы вы могли выгрузить.
источник
Классы имеют неявную строгую ссылку на свой экземпляр ClassLoader, и наоборот. Они мусор, как с объектами Java. Без использования интерфейса инструментов или подобного вам нельзя удалить отдельные классы.
Как всегда, вы можете получить утечки памяти. Любая сильная ссылка на один из ваших классов или загрузчик классов приведет к утечке. Это происходит, например, с реализациями Sun ThreadLocal, java.sql.DriverManager и java.beans.
источник
Если вы в прямом эфире наблюдаете, работает ли класс выгрузки в JConsole или как-то еще, попробуйте также добавить
java.lang.System.gc()
в конце логику выгрузки класса. Это явно вызывает сборщик мусора.источник