Як я можу написати програму Java, яка може оновлюватись під час виконання?


91

Я хотів би реалізувати Java-програму (серверну програму), яка може завантажити нову версію (файл .jar) із заданої URL-адреси, а потім оновити себе під час виконання.

Який найкращий спосіб це зробити і чи можливий?

Я думаю, що програма може завантажити новий файл .jar і запустити його. Але як мені зробити передачу, наприклад, знати, коли запускається нова програма, а потім вийти. Або є кращий спосіб зробити це?


4
Ви заглядали в Java Web Start? Він не оновлюється під час виконання, хоча, я вважаю, (потрібно перезапустити), для цього вам, мабуть, потрібно подивитися на OSGi.
Тіло

@Thilo: Я думаю, було б легко завантажити файл із заданої URL-адреси, а потім запустити його командою linux із запущеного файлу jar.
Jonas

1
Дизайн Java WebStart API унеможливлює оновлення під час роботи. На жаль.
Thorbjørn Ravn Andersen


@meain boss you rock, you made my day :)
iltaf khalid

Відповіді:


68

Основна структура рішення така:

  • Існує основний цикл, який відповідає за багаторазове завантаження останньої версії програми (якщо потрібно) та її запуск.

  • Додаток робить своє, але періодично перевіряє URL-адресу завантаження. Якщо він виявляє нову версію, він повертається до панелі запуску.

Існує низка способів це реалізувати. Наприклад:

  • Запуск може бути сценарієм обгортки або двійковою програмою, яка запускає нову JVM для запуску програми з файлу JAR, який замінюється.

  • Запуск може бути додатком Java, який створює завантажувач класів для нового JAR, завантажує клас точки входу і викликає в ньому якийсь метод. Якщо ви робите це таким чином, вам доведеться стежити за витоками сховища завантажувачів класів, але це не складно. (Вам просто потрібно переконатися, що жоден об’єкт із класами, завантаженими з JAR, недоступний після перезапуску.)

Перевагами підходу до зовнішньої обгортки є:

  • вам потрібен лише один JAR,
  • ви можете замінити всю програму Java,
  • будь-які вторинні потоки, створені додатком тощо, зникнуть без особливої ​​логіки вимкнення, і
  • Ви також можете мати справу з відновленням після збоїв програми тощо.

Другий підхід вимагає двох JAR, але має наступні переваги:

  • рішення - чиста Java і портативна,
  • перехід буде швидшим, і
  • Ви можете легше зберегти стан під час перезапуску (проблеми з витоками за модулем).

Найкращий спосіб залежить від ваших конкретних вимог.

Слід також зазначити, що:

  • Автоматичне оновлення має загрозу безпеці. Загалом, якщо сервер, що надає оновлення, скомпрометований або якщо механізми надання оновлень сприйнятливі до атак, то автоматичне оновлення може призвести до компрометації клієнтів.

  • Надсилання оновлень клієнту, які завдають йому шкоди, може мати юридичні ризики та ризик для репутації вашого бізнесу.


Якщо ви можете знайти спосіб уникнути винаходу колеса, це було б добре. Інші відповіді на пропозиції див.


43

Зараз я розробляю демон JAVA Linux Daemon, а також мав потребу в реалізації механізму автоматичного оновлення. Я хотів обмежити свою програму одним файлом jar і придумав просте рішення:

Запакуйте програму оновлення в саме оновлення.

Застосування : Коли програма виявляє новішу версію, вона робить наступне:

  1. Завантажити оновлення (Zipfile)
  2. Витяг застосунку та ApplicationUpdater (все у zip-файлі)
  3. Запустіть програму оновлення

ApplicationUpdater : Під час запуску програми оновлення робить наступне:

  1. Зупиніть програму (у моєму випадку демон через init.d)
  2. Скопіюйте завантажений файл jar, щоб замінити поточну програму
  3. Запустіть програму
  4. Прибирати.

Сподіваюся, це комусь допомагає.


12

Це відома проблема, і я рекомендую не винаходити колеса - не пишіть власні хаки, просто використовуйте те, що вже зробили інші люди.

Ви повинні врахувати дві ситуації:

  1. Додаток має бути самостійно оновлюваним і продовжувати працювати навіть під час оновлення (серверна програма, вбудовані програми). Ідіть з OSGi: Bundles або Equinox p2 .

  2. Додаток - це настільний додаток, який має програму встановлення. Є багато установників з можливістю оновлення. Перевірте список установників .


12

Нещодавно я створив update4j, який повністю сумісний з модульною системою Java 9.

Він легко запустить нову версію без перезапуску.


Використовуючи парадигму завантаження / бізнес-додатків. Завантажувальний ремінь завантажує та вивантажує бізнес-додаток, і це завантажувальне програмне забезпечення, як правило, оновлює.
Мордехай

10

Я написав додаток Java, який може завантажувати плагіни під час виконання та негайно починати їх використовувати, натхненний подібним механізмом у jEdit. jEdit є відкритим кодом, тому у вас є можливість подивитися, як це працює.

Рішення використовує спеціальний ClassLoader для завантаження файлів з банки. Після завантаження ви можете викликати якийсь метод із нової банки, який буде діяти як його mainметод. Тоді хитра частина гарантує, що ви позбудетеся всіх посилань на старий код, щоб він міг збирати сміття. Я не зовсім фахівець у цій частині, я змусив це працювати, але це було непросто.


Я не знаю про Java, але в C # ви можете використовувати AppDomains для явного вивантаження коду. Можливо, існує схожа концепція в Java.
Merlyn Morgan-Graham

1
Дякую, це, здається, шлях. Є приклад a NetworkClassLoaderна JavaDoc для ClassLoader
Jonas

Ви стикалися з проблемами зі статичними змінними в тій самій JVM, або як щодо постійного покоління? Я чув, що ці проблеми можуть спричинити розвантаження класу.
ide

5
  1. Перший спосіб: використовуйте tomcat і його засоби розгортання.
  2. Другий спосіб: розділити додаток на дві частини (функціональну та оновлену) і дозволити оновленій частині замінити функціональну частину.
  3. Третій спосіб: У додатку вашого сервера просто завантажте нову версію, потім стара версія звільняє прив'язаний порт, потім стара версія запускає нову версію (запускає процес), потім стара версія надсилає запит через порт програми до нової версії для видалення старої версії, старої версії припиняється, а нова версія видаляє стару версію. Подобається це: текст заміщення

Ваш другий спосіб здається цікавим дизайном.
Jonas

2

Це не обов'язково найкращий спосіб, але він може працювати для вас.

Ви можете написати програму для завантаження (але, запуск у World of Warcraft, якщо ви грали в WoW). Цей завантажувальний файл відповідає за перевірку наявності оновлень.

  • Якщо оновлення доступне, воно запропонує його користувачеві, здійснить завантаження, встановлення тощо.
  • Якщо програма оновлена, це дозволить користувачеві запустити програму
  • За бажанням ви можете дозволити користувачеві запускати програму, навіть якщо вона не оновлена

Таким чином, вам не доведеться турбуватися про примусовий вихід програми.

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

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

Зверніть увагу, що я не знаю, чи може Java викликати код інтерфейсу перед тим, як відкрити головне вікно. Ми використовували C # / WPF.


Дякую, це хороший спосіб це зробити. Але це серверна програма, тому немає жодного користувача, який може вжити певних дій. І я вважаю за краще, щоб це був лише один файл jar, тому користувач easyli може завантажити одну jar і запустити її на початку, але після цього я хотів би не мати взаємодії з користувачем.
Jonas

Коли ви говорите "серверна програма", ви маєте на увазі, що це програма, яка запускається безпосередньо на сервері під час входу в систему?
Merlyn Morgan-Graham

@Jonas: Я не дуже добре розумію, як працюють файли .jar, тому я не можу там бути корисним. Я можу зрозуміти, чи віддаєте Ви перевагу відповіді, яка стосується Java. Сподіваємось, це дає вам принаймні роздуми :)
Мерлін Морган-Грем

@Merlyn: Я вдячна за поділ вашими ідеями. Так, це програма Java, яка працюватиме на сервері Linux, і на цьому сервері ніхто не входить в систему.
Jonas

1
@Jonas: Не те, що ви ще не думали про це, але - Більшість веб-служб, які я бачив, мають стратегію розгортання вручну. Можливо, ви захочете бути обережними щодо перевірки наявності оновлень. Якщо ви натискаєте на помилку / непрацюючий код або виконуєте лише частково за допомогою розгортання декількох файлів, сервер може спробувати оновити себе, і тоді у вас буде зламаний сервер.
Merlyn Morgan-Graham

2

Якщо ви створюєте свою програму за допомогою плагінів Equinox , ви можете скористатися системою підготовки P2, щоб отримати готове рішення цієї проблеми. Для цього потрібно буде перезапустити сервер після оновлення.


1

Я бачу проблему безпеки під час завантаження нової банки (тощо), наприклад, людина в середині атаки. Завжди потрібно підписувати оновлення, яке можна завантажити.

На JAX2015 Адам Бієн розповів про використання JGit для оновлення бінарних файлів. На жаль, я не зміг знайти підручників.

Джерело німецькою мовою.

Адам Бієн створив програму оновлення, див. Тут

Я розгалужив його тут за допомогою інтерфейсу javaFX. Я також працюю над автоматичним підписанням.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.