java:必要に応じてプログラムを再起動させる方法は?



Java How Make Program Restart Itself



なぜ自己再開するのですか?

シーン1: 分散環境では、一般に、さまざまな環境にデプロイされた多くのアプリケーション(c / sのJavaアプリケーションとb / sのWebアプリケーションを含む)があります。管理の便宜のために、通常、次のようないくつかの一般的な構成が設定されます。アラーム電子メールの電子メールアカウント/パスワード/ smtp情報、パブリックftpアカウント情報、さらにはjdbc接続文字列情報などが統一された場所(共有ネットワークストレージ)に配置されますディレクトリ、redisキャッシュ、データベース、zookeeper、リモートサービス)任意)、管理する方が便利です。幸いなことに、メールアカウントなどの情報は良いです。各アプリケーションのサブスクリプション構成が変更されたときに、変更が見つかった場合、それがSpring環境である場合は、applicationContext.refresh()を直接呼び出すと、構成が更新されます。ただし、データソースの特別な構成の場合、理解するのはより困難です。正常に接続された接続プール内の接続オブジェクト、古いデータソースから検出されたデータ、古いデータソースに関連付けられたsqlSesstionFactory、Mapperインスタンスなどを考慮する必要があります。全血を保証することは困難です。両替。最良の方法は、プログラムを再起動することです。



シーン2: プログラムを書くとき、隠れたバグがあることは避けられません。バグがまったくないプログラムはまだ非常にまれです。プログラムの実行時間が増加し続けているためにプログラムのパフォーマンスが悪化したり、仮死状態になったりした場合は、再起動する必要があります。通常はリモートクラッシュです。Linuxの場合は、コマンドkillプロセスを押してから、Javaアプリケーションを再起動します。これは、Linuxに慣れていない初心者の管理者にはなじみがなく、実行権限がない可能性があるため、使いやすい監視管理インターフェイスを使用して、再起動ボタンをクリックします。指定したプログラムを再起動すると、受け入れやすくなります。

テキストの始まり:



1.プログラムは、再起動する必要があることをどのように認識しますか?

もちろん、プログラムがある場合、ユーザーが正常にシャットダウンしたい場合、プログラムは自動的に再起動し、このサイクルはシャットダウンできない悪意のあるプログラムになります。に

したがって、プログラムは別のプロセスで監視し、プログラムを正常に閉じるようにユーザーに影響を与えることなく、特定の指示を受け取る必要があります。アイデア:



プログラムが起動すると、一意のuuid(またはグローバルに一意である場合は他の識別子)が生成され、一時ノードがzookeeperに登録されます。に

といった:

/ app / uuid-1

このようにして、監視センターは、/ appの下にある一時ノードの数をスキャンする限り、現在実行中のアプリケーションを認識します。に

管理者が監視センターからアプリケーションを再起動したい場合、管理者は動物園の飼育係にノードを書き込むことができます

/ command / uuid-1ノードの内容、規則は次のとおりです。再起動

アプリケーションの起動後、/ command / uuid-1ノードのデータ変更を監視します。再起動のデータ内容が見つかると、再起動命令を受信したと見なされ、次の処理に従って自己破壊して転生します。

次に、Javaアプリケーションを再起動します

インターネット上のサンプルコード:

Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { try { String restartCmd = 'nohup java -jar xxx.jar' Thread.sleep(10000)//Wait for 10 seconds to ensure that the clone is started and then shut down logger.debug('Program restart complete!') } catch (Exception e) { logger.error('Restart failed, reason:', e) } } }) logger.debug('The program is ready to restart!') System.exit(0)

改善できる点:

a)sleep(10000)つまり、10秒間待ってから、「クローン」がアクティブ化された後、自分の「実体」を殺します。ここでの10秒は、実際には頭によって設定されます。理論的に言えば、完璧を追求しているのであれば、新しく活性化された「クローン」がシステムプロセスに現れる限り、「実体」の人間性は破壊される可能性があります。

問題: 「クローン」がアクティブ化されていることを知っている場合は?

回答: Javaはjps-lの出力を取得し、現在のすべてのJavaプロセスを認識できるため、指定されたアプリケーションが起動されているかどうかを知ることができます。再起動する前に、jps-lの出力を1回取得できます。再起動後、jps -lの出力を再度実行し、2番目の出力を比較します。新しく指定されたプロセス名が見つかった場合は、「クローン」が開始されたことを意味します。自分を終わらせる。

添付ファイル:jps出力を取得するためのJavaコード

import org.apache.logging.log4j.* import java.io.BufferedReader import java.io.InputStreamReader public final class RuntimeUtil { private static Logger logger = LogManager.getLogger() public static String exec(String command) { StringBuilder sb = new StringBuilder() try { Process process = Runtime.getRuntime().exec(command) BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())) String line = null while ((line = reader.readLine()) != null) { sb.append(line) } process.getOutputStream().close() reader.close() process.destroy() } catch (Exception e) { logger.error('External command execution error, command line:' + command, e) } return sb.toString() } public static String jps() { return exec('jps -l') } }

b)ここでのjava -jar xxx.jarはあまり良くありません。1つはxxx.jarが文字列であり、コンパイル中にエラーが見つからないこと、もう1つはパスが相対パスであることです。起動に成功しても、jpsが表示する最終的なプロセス名はjarです。実際にどのプログラムに対応しているかわかりません(詳しくはこちらをご覧ください) java-jarのプロセス表示名を設定します )、現在のプログラムの実際のパスを取得するようにコーディングできます

public static String getJarExecPath(Class clazz) { String path = clazz.getProtectionDomain().getCodeSource().getLocation().getPath() if (OSUtil.getOSname().equals(OSType.Windows)) { return path.substring(1) } return path }