it-swarm.com.ru

Как я могу написать приложение Java, которое может обновляться во время выполнения?

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

Каков наилучший способ сделать это и возможно ли это?

Я предполагаю, что приложение может загрузить новый файл .jar и запустить его. Но как мне сделать передачу, например знать, когда новое приложение запускается, а затем выйти. Или есть лучший способ сделать это?

78
Jonas

Основная структура решения выглядит следующим образом:

  • Существует основной цикл, отвечающий за повторную загрузку последней версии приложения (при необходимости) и ее запуск.

  • Приложение делает свое дело, но периодически проверяет URL загрузки. Если он обнаруживает новую версию, он возвращается обратно в панель запуска.

Есть несколько способов, которыми вы могли бы реализовать это. Например:

  • Средство запуска может быть сценарием-оболочкой или двоичным приложением, которое запускает новую JVM для запуска приложения из файла JAR, который заменяется.

  • Средство запуска может быть приложением Java, которое создает загрузчик классов для нового JAR, загружает класс точки входа и вызывает для него некоторый метод. Если вы делаете это таким образом, вы должны следить за утечками памяти в загрузчиках классов, но это не сложно. (Вам просто нужно убедиться, что ни один объект с классами, загруженными из JAR, не будет доступен после перезапуска.)

Преимущества подхода внешней обертки:

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

Второй подход требует двух JAR, но имеет следующие преимущества:

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

«Лучший» способ зависит от ваших конкретных требований.

Следует также отметить, что:

  • При автоматическом обновлении существуют угрозы безопасности. В целом, если сервер, предоставляющий обновления, скомпрометирован или если механизмы предоставления обновлений подвержены атакам, автоматическое обновление может привести к компрометации клиента (ов).

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


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

55
Stephen C

В настоящее время я занимаюсь разработкой Java Linux Daemon, а также мне нужно было реализовать механизм автообновления. Я хотел ограничить свое приложение одним jar-файлом и предложил простое решение: 

Упакуйте приложение обновления в само обновление.

Приложение : Когда приложение обнаруживает более новую версию, оно делает следующее:

  1. Скачать обновление (Zipfile)
  2. Извлечь Application и ApplicationUpdater (все в zipfile)
  3. Запустить обновление

ApplicationUpdater : Когда запускается программа обновления, она делает следующее:

  1. Остановите приложение (в моем случае это демон через init.d)
  2. Скопируйте загруженный файл JAR, чтобы перезаписать текущее приложение
  3. Запустите приложение
  4. Cleanup.

Надеюсь, это поможет кому-то.

35
Berdus

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

Решение использует пользовательский ClassLoader для загрузки файлов из фляги. После загрузки вы можете вызвать какой-либо метод из нового jar, который будет действовать как его метод main. Затем сложная задача - убедиться, что вы избавились от всех ссылок на старый код, чтобы его можно было собирать мусором. Я не совсем эксперт в этой части, я заставил это работать, но это было нелегко.

10
Brad Mace

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

Вам нужно рассмотреть две ситуации:

  1. Приложение должно быть самообновляемым и продолжать работать даже во время обновления (серверное приложение, встроенные приложения). Перейти с OSGi: Связки или Equinox p2 .

  2. Приложение является настольным приложением и имеет установщик. Есть много инсталляторов с возможностью обновления. Проверьте список установщиков .

9
Peter Knego
  1. Первый способ: использовать Tomcat и его средства развертывания.
  2. Второй способ: разделить приложение на две части (функциональная и обновленная) и позволить обновленной части заменить функциональную часть.
  3. Третий способ: в вашем серверном приложении просто загрузите новую версию, затем старая версия освобождает связанный порт, затем старая версия запускает новую версию (запускает процесс), затем старая версия отправляет запрос на порт приложения новой версии, чтобы удалить старую версию, старую версию завершается и новая версия удаляет старую версию. Как это:alt text
5
jnr

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

Он без проблем запустит новую версию без перезапуска.

4
Mordechai

Если вы создаете свое приложение с помощью Equinox plugins, вы можете использовать P2 Provisioning System , чтобы получить готовое решение этой проблемы. Это потребует перезагрузки сервера после обновления.

2
Tom Crockett

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

Вы можете написать приложение начальной загрузки (а также пусковую установку World of Warcraft, если вы играли в WoW). Этот загрузчик отвечает за проверку обновлений.

  • Если доступно обновление, оно предложит его пользователю, выполнит загрузку, установку и т.д.
  • Если приложение обновлено, оно позволит пользователю запустить приложение
  • При желании вы можете разрешить пользователю запускать приложение, даже если оно не обновлено

Таким образом, вам не нужно беспокоиться о принудительном выходе из приложения.

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

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

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

2
Merlyn Morgan-Graham

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

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

Источник на немецком языке.

Адам Бьен создал программу обновления смотрите здесь

Я разветвлял это здесь с некоторым интерфейсом javaFX. Я также работаю над автоматической подписью.

0
Kaito