Вивантаження занять у java?


174

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

Тепер я просто потрапив на проблему, коли мені потрібно поговорити з двома різними AppServers і виявив, що залежно від того, чиї класи я завантажую спочатку, я можу погано зламатись ... Чи є спосіб змусити розвантажити клас, не фактично вбивши JVM?

Сподіваюся, це має сенс


У вас є завантажувач класів для кожної банки? Як архіви контейнерів OSGI завантажують завантажувач класів? Схоже, немає API розвантаження в класі завантажувача?
hetaoblog

Відповіді:


190

Єдиний спосіб, що Клас може бути вивантажений, це якщо використовуваний завантажувач класів збирається сміттям. Це означає, що посилання на кожен клас та на сам завантажувач класів повинні йти шляхом dodo.

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

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

Якщо ви не хочете використовувати OSGI, можливою реалізацією може бути використання одного примірника класу JarClassloader для кожного файлу JAR.

І створити новий клас MultiClassloader, який розширює Classloader. Цей клас внутрішньо матиме масив (або Список) JarClassloaders, а в методі defineClass () буде перебиратися через усі внутрішні завантажувачі класів, поки не буде знайдено визначення або не буде викинуто NoClassDefFoundException. Для додавання нових JarClassloaders до класу можна надати кілька методів аксесуарів. У мережі є кілька можливих реалізацій для MultiClassLoader, тому вам може навіть не потрібно писати власні.

Якщо ви створюєте екземпляр MultiClassloader для кожного з'єднання з сервером, в принципі можливо, кожен сервер використовує іншу версію одного класу.

Я використовував ідею MultiClassloader в проекті, де класи, які містили визначені користувачем сценарії, повинні були завантажуватися та вивантажуватися з пам'яті, і це працювало досить добре.


31
Зауважимо також, що згідно з java.sun.com/docs/books/jls/second_edition/html/… розвантаження класів є оптимізацією і, залежно від реалізації JVM, може бути, а може і не відбуватися.

5
Як простішу і легку альтернативу OSGi, спробуйте JBoss Modules - модульоване завантаження класів із завантажувачем класів на модуль (група банок).
Ondra Žižka

42

Так, є способи завантаження класів і згодом "розвантаження" їх. Трюк полягає в тому, щоб реалізувати свій власний завантажувач класів, який знаходиться між завантажувачем класів високого рівня (завантажувач класу систем) та завантажувачем класів на серверах додатків, і сподіватися, що завантажувачі класів сервера додатків делегують завантаження класу верхнім навантажувачем .

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

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

Зроблене право не повинно настати ClassCastException або LinkageError і т.д.

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


3
Я не розумію людей, які поставили галочку -1 за цю відповідь, не залишаючи коментарів. Для мене добре виглядає. Можливо, мати одного ClassLoaderв класі трохи більше, а один ClassLoaderна JAR має сенс. Може бути конкретніше щодо того, як змусити завантажувати клас у запропонованій схемі? Наприклад, як я можу гарантувати, що екземпляри класів, завантажених ClassLoaderA, не посилаються на екземпляри, завантажені ClassLoaderB?
dma_k

@dma_k точно, відповідь хороша, але вона не торкається ключових моментів, які ви згадали.
цинк

@Georgi чи існує така реалізація, яку ми можемо встановити / повторно використати для цього?
Санки

1
Було б дуже корисно, якби ви могли надати зразок java-коду. Щоб бути точним, я шукаю як розвантажити класи за допомогою CustomClassLoader, але не пощастило.
Шріхарша грв

@ Sriharshag.rv Ви спробували це і реалізували зразок?
niaomingjian

17

Я написав спеціальний завантажувач класів, з якого можна вивантажувати окремі класи без GCing класного завантажувача. Навантажувач класу Jar


Працює як шарм :). Чи є який-небудь метод для вивантаження всіх файлів класу jar-файлу?
Ерксен

На жаль, наразі немає. Але розберемося. Можливо, у наступних випусках.
Камран

До речі, я знайшов трохи вирішення. Якщо у вас є один JarClassLoaderдля кожного завантаженого файлу jar, ви можете зателефонувати getLoadedClasses()на нього, потім перебрати його та вивантажити.
Ercksen

12

Навантажувачі класів можуть бути складною проблемою. Особливо ви можете зіткнутися з проблемами, якщо ви використовуєте кілька завантажувачів класів і не чітко та чітко визначені їх взаємодії. Я думаю, що для того, щоб насправді вдалося розвантажити клас, який ти збираєшся, потрібно видалити всі посилання на будь-які класи (та їх екземпляри), які ти намагаєшся вивантажити.

Більшість людей, які потребують цього виду, в кінцевому підсумку використовують OSGi . OSGi дійсно потужний і дивно легкий і простий у використанні,


7

Ви можете вивантажити ClassLoader, але не можете вивантажити конкретні класи. Більш конкретно, ви не можете вивантажувати класи, створені в ClassLoader, який не є вашим контролем.

Якщо можливо, я пропоную використовувати власний ClassLoader, щоб ви могли розвантажуватись.


4

Класи мають неявну чітку посилання на їх екземпляр ClassLoader, і навпаки. Вони зібрані сміття, як і з об'єктами Java. Не вдаряючи інтерфейс інструментів або подібне, ви не можете видалити окремі класи.

Як завжди, ви можете отримати витоки пам'яті. Будь-яка чітка посилання на один із ваших класів або навантажувача класів випустить всю справу. Це відбувається, наприклад, з Sun-реалізаціями ThreadLocal, java.sql.DriverManager та java.beans.


-1

Якщо ви дивитесь наживо, чи працював розвантажувальний клас у JConsole чи щось подібне, спробуйте також додати java.lang.System.gc()наприкінці логіки розвантаження класу. Це явно запускає сміттєзбірник.


3
Обережно: System.gc () не потрібно викликати GC. Він лише просить jvm запустити його, але він не застосовує його. І IME часто не запускайте GC: - \
Juh_
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.