kagamihogeの日記

kagamihogeの日記です。

Spring BatchのCommandLineJobRunnerで任意の終了ステータスを返す

背景

たとえば、Spring BatchをCommandLineJobRunnerを使用するjavaコマンドで起動し、そのjavaプロセスの終了ステータスをシェルスクリプトで取得して何らかの条件分岐を行いたい、とする。基本的には、Spring Batchはその終了状態に応じて0,1,2を返すのでこれで十分なのだが、それ以外の任意の値を返したい場合がある。

ソースコードなど

環境

  • spring-batch 3.0.7.RELEASE

JVM終了時に呼ばれるSystemExiter

CommandLineJobRunnerはJVM呼び出し時の拡張ポイントとしてpresetSystemExiterを用意しているので、ここで自前のSystemExiterを設定できる。

import org.springframework.batch.core.launch.support.CommandLineJobRunner;
import org.springframework.batch.core.launch.support.SystemExiter;

...
    public static void main(String[] args) throws Exception {
        CommandLineJobRunner.presetSystemExiter(new SystemExiter() {
            public void exit(int status) {
                System.exit(status);
            }
        });
        CommandLineJobRunner.main(args);
    }

ちなみにEclipseで終了ステータスを確認するにはdebugビューで見れる。

f:id:kagamihoge:20170625183723j:plain

afterJobでExitStausのexitCodeを指定してExitCodeMapperで変換

上のコードは固定値だが、exitメソッドのstatusは基本的にはExitStatusの値が入ってくる。ただし、CommandLineJobRunnerデフォルト動作のSimpleJvmExitCodeMapperが0,1,2のいずれかにExitStatusの値を変換する。そのため、それ以外の値にしたければ自前のExitCodeMapperを設定してやる必要がある。

まず、適当な終了ステータスのExitStatusを返すJobExecutionListenerを作る。リスナ設定のXMLなどについては省略。

import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobExecutionListener;

public class JobListener implements JobExecutionListener {

    @Override
    public void beforeJob(JobExecution jobExecution) {
    }

    @Override
    public void afterJob(JobExecution jobExecution) {
        jobExecution.setExitStatus(new ExitStatus("114"));
    }

}

自前のExitCodeMapperを作る。ここでは、単にExitStatusのexitCode文字列をintに変換するだけ。上記のJobListener#afterJobでexitCodeに114の文字列を指定しているので、以下のメソッドはintの114を返す。

import org.springframework.batch.core.launch.support.SimpleJvmExitCodeMapper;

public class CustomExitCodeMapper extends SimpleJvmExitCodeMapper {
    @Override
    public int intValue(String exitCode) {        
        return Integer.parseInt(exitCode);
    }
}

次に、CommandLineJobRunnerにsetExitCodeMapperがあるので、これを使用してセッターインジェクションで、上で作成した自前のCustomExitCodeMapperを設定する。方法は色々あるが、たとえばXMLなら以下のようにする。

<bean id="exitCodeMapper" class="kagamihoge.springbatchexitcode.CustomExitCodeMapper" />

ここの仕組みについては、CommandLineJobRunnerは起動時に引数に与えられたxmlをスキャンし、それを自身にも適用している。なので、たとえばsetExitCodeMapperに対応するexitCodeMapperというidのbeanがあればそれをインジェクションする。

最後に、最初に作成したSystemExiterのところを引数の値をそのままSystem.exitの引数に渡すように変更する。

       CommandLineJobRunner.presetSystemExiter(new SystemExiter() {
            public void exit(int status) {
                System.exit(status);
            }
        });

これで、afterJobで何らかの条件分岐を行い、それを基に任意の終了ステータスを返すことが出来る。

参考URL