web-dev-qa-db-ja.com

実行時に自身を更新できるJavaアプリケーションを作成するにはどうすればよいですか?

特定のURLから新しいバージョン(.jarファイル)をダウンロードし、実行時に自分自身を更新できるJavaアプリケーション(サーバーアプリケーション)を実装したいと思います。

これを行う最善の方法は何ですか?それは可能ですか?

アプリケーションが新しい.jarファイルをダウンロードして起動できると思います。しかし、どのようにハンドオーバーを行うべきですか?新しいアプリケーションがいつ開始されたかを確認してから終了します。または、これを行うためのより良い方法はありますか?

81
Jonas

ソリューションの基本構造は次のとおりです。

  • アプリの最新バージョン(必要な場合)を繰り返し読み込み、起動するメインループがあります。

  • アプリケーションは処理を行いますが、ダウンロードURLを定期的にチェックします。新しいバージョンを検出すると、終了してランチャーに戻ります。

これを実装する方法はいくつかあります。例えば:

  • ランチャーは、ラッパースクリプトまたは新しいJVMを起動して、置き換えられるJARファイルからアプリケーションを実行するバイナリアプリケーションにすることができます。

  • ランチャーはJava新しいJAR用のクラスローダーを作成し、エントリポイントクラスをロードし、そのメソッドを呼び出すアプリケーションです。この方法で行う場合、クラスローダーストレージを監視する必要がありますリークしますが、それは難しくありません(再起動後、JARからロードされたクラスを持つオブジェクトが到達できないことを確認する必要があります)。

外部ラッパーアプローチの利点は次のとおりです。

  • 必要なJARは1つだけです。
  • Java app、
  • アプリなどによって作成されたセカンダリスレッドは、特別なシャットダウンロジックなしで消滅します。
  • アプリケーションのクラッシュなどからの回復にも対処できます。

2番目のアプローチには2つのJARが必要ですが、次の利点があります。

  • 解決策は純粋なJavaと移植性、
  • 切り替えがより迅速になり、
  • 再起動後も状態をより簡単に保持できます(モジュロリークの問題)。

「最良の」方法は、特定の要件によって異なります。

次の点にも注意する必要があります。

  • 自動更新にはセキュリティ上のリスクがあります。一般に、更新を提供するサーバーが危険にさらされている場合、または更新を提供するメカニズムが攻撃を受けやすい場合、自動更新によりクライアントが危険にさらされる可能性があります。

  • クライアントに損害を与える更新をクライアントにプッシュすると、法的リスク、およびビジネスの評判に対するリスクが生じる可能性があります。


車輪の再発明を避ける方法を見つけることができれば、それは良いことです。提案については、他の回答を参照してください。

58
Stephen C

現在、Java Linux Daemonを開発しています。また、自動更新メカニズムを実装する必要がありました。アプリケーションを1つのjarファイルに制限したかったので、簡単な解決策を思い付きました。

アップデーターアプリケーションをアップデート自体にパックします。

アプリケーション:アプリケーションが新しいバージョンを検出すると、次のことを行います。

  1. アップデートのダウンロード(Zipfile)
  2. アプリケーションの抽出およびApplicationUpdater(すべてzipファイル内)
  3. アップデーターを実行する

ApplicationUpdater:アップデーターが実行されると、以下を実行します。

  1. アプリケーションを停止します(私の場合、init.d経由のデーモン)
  2. ダウンロードしたjarファイルをコピーして、現在のアプリケーションを上書きします
  3. アプリケーションを開始する
  4. 掃除。

それが誰かを助けることを願っています。

37
Berdus

Javaランタイムでプラグインをロードし、すぐに使用を開始できるアプリケーションを作成しました。jEditの同様のメカニズムに触発されました。jEditはオープンソースであるため、できます。

このソリューションでは、カスタムClassLoaderを使用して、jarからファイルをロードします。ロードされたら、mainメソッドとして機能する新しいjarからメソッドを呼び出すことができます。トリッキーな部分は、古いコードへのすべての参照を確実に削除して、ガベージコレクションできるようにすることです。私はその部分の専門家ではありません。機能させましたが、簡単ではありませんでした。

10
Brad Mace

これは既知の問題であり、車輪の再発明を避けることをお勧めします-自分でハックを書くのではなく、他の人がすでにやったことを使ってください。

考慮する必要がある2つの状況:

  1. アプリは自己更新可能で、更新中でも実行し続ける必要があります(サーバーアプリ、組み込みアプリ)。 OSGiを使用します: Bundles または Equinox p2

  2. アプリはデスクトップアプリであり、インストーラーがあります。更新オプションを備えた多くのインストーラーがあります。 インストーラーリスト を確認します。

9
Peter Knego
  1. 最初の方法:Tomcatを使用し、それを展開する機能です。
  2. 2番目の方法:アプリケーションを2つの部分(機能部分と更新部分)に分割し、更新部分を機能部分に置き換えます。
  3. 3番目の方法:サーバーアプリケーションで新しいバージョンをダウンロードし、古いバージョンがバインドされたポートをリリースし、古いバージョンが新しいバージョンを実行し(プロセスを開始)、古いバージョンが古いバージョンを削除するために新しいバージョンにアプリケーションポートで要求を送信します終了し、新しいバージョンが古いバージョンを削除します。このような: alt text
5
jnr

最近、 pdate4j を作成しました。これは、Java 9のモジュールシステムと完全に互換性があります。

再起動せずに新しいバージョンをシームレスに起動します。

5
Mordechai

これは必ずしもbestの方法ではありませんが、うまくいくかもしれません。

bootstrapアプリケーション(WoWをプレイしている場合はWorld of Warcraftランチャー))を記述できます。そのbootstrapは更新の確認を担当します。

  • 更新が利用可能な場合、ユーザーに提供し、ダウンロード、インストールなどを処理します。
  • アプリケーションが最新の場合、ユーザーはアプリケーションを起動できます。
  • オプションで、最新ではない場合でもユーザーにアプリケーションの起動を許可できます。

これにより、アプリケーションを強制終了することを心配する必要がなくなります。

アプリケーションがWebベースであり、最新のクライアントを持っていることが重要な場合は、アプリケーションの実行中にバージョンチェックを行うこともできます。サーバーとの通常の通信(一部またはすべての呼び出し)、またはその両方を実行しながら、間隔を空けて行うことができます。

私が最近取り組んだ製品については、起動時(ブートストラップアプリなしで、メインウィンドウが表示される前)、およびサーバーへの呼び出し中にバージョンチェックを行いました。クライアントが古くなった場合、ユーザーが手動で終了することに依存していましたが、サーバーに対するアクションは禁止されていました。

Javaがメインウィンドウを表示する前にUIコードを呼び出すことができるかどうかはわかりません。C#/ WPFを使用していました。

Equinox プラグインを使用してアプリケーションを構築する場合、 P2 Provisioning System を使用して、この問題に対する既製のソリューションを取得できます。これには、更新後にサーバーを再起動する必要があります。

1
Tom Crockett

新しいjarファイル(など)をダウンロードするときに、セキュリティの問題が発生します(中間者攻撃など)。ダウンロード可能なアップデートに常に署名する必要があります。

JAX2015で、Adam Bienはバイナリの更新にJGitを使用することについて語りました。悲しいことに、チュートリアルが見つかりませんでした。

ドイツ語のソース。

Adam Bienがアップデータを作成しました こちらを参照

私はそれをフォークしました ここ いくつかのjavaFXフロントエンドで。自動署名にも取り組んでいます。

0
Kaito