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


91

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

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

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


4
Java Web Startを見たことがありますか?ただし、実行時にそれ自体は更新されません(おそらく再起動が必要です)。そのため、おそらくOSGiを確認する必要があります。
Thilo

@チロ:与えられたURLからファイルをダウンロードし、実行中のjarファイルからLinuxコマンドでそれを開始するのは簡単だと思います。
ジョナス

1
Java WebStart APIの設計により、実行中に更新することはできません。残念ながら。
するThorbjörnRavnアンデルセン


@meainボス、あなたはロックし、あなたは私の日を作った:)
iltaf khalid '05 /

回答:


67

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

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

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

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

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

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

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

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

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

  • ソリューションは純粋なJavaであり、移植可能です。
  • 切り替えが速くなり、
  • 再起動後の状態をより簡単に保持できます(モジュロリーケージの問題)。

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

次の点にも注意してください。

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

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


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


43

私は現在、JAVA Linuxデーモンを開発しており、自動更新メカニズムを実装する必要もありました。アプリケーションを1つのjarファイルに制限したかったので、簡単な解決策を考え出しました。

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

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

  1. 更新のダウンロード(Zipfile)
  2. アプリケーションとApplicationUpdaterを抽出します(すべてzipファイルにあります)
  3. アップデーターを実行

ApplicationUpdater:アップデーターが実行されると、次のことを行います。

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

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


12

これは既知の問題であり、ホイールを再発明しないことをお勧めします。独自のハックを作成せず、他の人がすでに行っていることを使用してください。

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

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

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


12

私は最近、Java 9のモジュールシステムと完全に互換性のあるupdate4jを作成しました。

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


ブートストラップ/ビジネスアプリケーションパラダイムを使用する。ブートストラップはビジネスアプリケーションをロードおよびアンロードし、一般に更新を行うのはブートストラップです。
モルデチャイ

10

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

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


Javaについては知りませんが、C#ではAppDomainsを使用してコードを明示的にアンロードできます。たぶん、Javaにも同様の概念があります。
Merlyn Morgan-Graham、

1
ありがとう、これは進むべき道のようです。ClassLoaderNetworkClassLoaderのJavaDocに例があります
Jonas

同じJVM内の静的変数で問題が発生しましたか、それとも永続的な世代はどうですか?これらは、クラスのアンロードに関して問題を引き起こす可能性があると聞いています。
2010年

5
  1. 最初の方法:tomcatを使用すると、設備が配備されます。
  2. 2番目の方法:アプリケーションを2つの部分(機能部分と更新部分)に分割し、更新部分を機能部分に置き換えます。
  3. 3番目の方法:サーバーアプリケーションでは、新しいバージョンをダウンロードしてから、古いバージョンがバインドされたポートを解放し、古いバージョンが新しいバージョンを実行して(プロセスを開始)、古いバージョンがアプリケーションポートで新しいバージョンにリクエストを送信して、古いバージョン、古いバージョンを削除します終了し、新しいバージョンは古いバージョンを削除します。このような: 代替テキスト

2つ目の方法は、興味深いデザインのようです。
Jonas

2

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

ブートストラップアプリケーションを作成できます(WoWをプレイしたことがある場合は、World of Warcraftランチャーを使用します)。そのブートストラップは、更新のチェックを担当します。

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

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

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

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

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


ありがとう、それはそれを行う良い方法です。ただし、これはサーバーアプリケーションであるため、なんらかのアクションを実行できるユーザーは存在しません。そして、私はそれが単一のjarファイルであることが望ましいので、ユーザーeasyliは単一のjarをダウンロードして最初からそれを開始することができますが、その後はユーザーとのやり取りはありません。
ジョナス

「サーバーアプリケーション」とは、ログイン中にサーバー上で直接実行されるアプリケーションのことですか。
Merlyn Morgan-Graham、

@ジョナス:.jarファイルのしくみがよくわからないので、あまりサービスを提供できません。Javaに固有の回答を希望するかどうかを理解できます。うまくいけば、これは少なくともあなたに思考の糧を与えます:)
Merlyn Morgan-Graham

@マーリン:あなたのアイデアを共有してくれてありがとう。はい、これはLinuxサーバーで実行されるJavaアプリケーションであり、そのサーバーには誰もログインしていません。
Jonas

1
@ジョナス:あなたはこれについてまだ考えていなかったわけではありませんが、-私が見たほとんどのウェブサービスは手動の展開戦略を持っています。アップデートの確認方法に注意する必要がある場合があります。バギー/壊れたコードを押し上げるか、マルチファイルの展開で途中までしか行われない場合、サーバーはそれ自体を更新しようとする可能性があり、それによってサーバーが壊れます。
Merlyn Morgan-Graham、


1

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

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

ドイツ語のソース。

Adam Bienがアップデータ作成しました。こちらをご覧ください

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.