Spring批处理返回自定义流程退出代码

时间:2018-06-19 14:46:11

标签: java spring spring-boot jvm exit-code

我有一个罐子里有多个作业,我想每次只执行一个作业并检索自定义退出代码。

例如,我有一个基本的作业(retrieveErrorsJob)配置,其中一个步骤将读取输入的XML文件并将数据写入特定的数据库表中。

应用程序类

@SpringBootApplication
@EnableBatchProcessing
@Import(CoreCommonsAppComponent.class)
public class Application {

    private static final Logger logger = LoggerFactory.getLogger(Application.class);
    private ConfigurationConstants constants;

    @Autowired
    public Application(ConfigurationConstants constants) {
        this.constants = constants;
    }

    @EventListener(ApplicationStartedEvent.class)
    public void idApplication()
    {
        logger.info("================================================");
        logger.info(constants.APPLICATION_NAME() + "-v." + constants.APPLICATION_VERSION() + " started on " + constants.REMOTE_HOST());
        logger.info("------------------------------------------------");
    }

    public static void main(String... args) throws Exception{
        ApplicationContext context = SpringApplication.run(Application.class, args);
        logger.info("================================================");
        SpringApplication.exit(context);
    }
}

我可以从命令行选择一项工作:

java -jar my-jar.jar --spring.batch.job.names=retrieveErrorsJob --input.xml.file=myfile.xml

Spring Batch开始正确的工作。

问题是我需要jar返回自定义进程退出整数,例如ExitCode.FAILED == 4等。但是我总是有一个零(如果ExitCode = SUCCESS或FAILED)。

根据文档,我需要实现ExitCodeMapper接口。

代码(未完成)

public class CustomExitCodeMapper implements ExitCodeMapper {

private static final int NORMAL_END_EXECUTION = 1;
private static final int NORMAL_END_WARNING = 2;
private static final int ABNORMAL_END_WARNING = 3;
private static final int ABNORMAL_END_ERROR = 4;

@Override
public int intValue(String exitCode) {

    System.out.println("EXIT CODE = " + exitCode);

    switch (exitCode)
    {
        case "FAILED":
            return ABNORMAL_END_WARNING;
        default:
            return NORMAL_END_EXECUTION;
    }
}

}

我找不到使用此自定义实现的方法。我可以将自定义实现设置为CommandLineJobRunner,但如何使用此类?

3 个答案:

答案 0 :(得分:2)

由于@Mahendra,我有了一个主意:)

我已经按照@Mahendra的建议创建了一个JobCompletionNotificationListener类:

@Component
public class JobCompletionNotificationListener extends JobExecutionListenerSupport {

    private static final Logger logger = LoggerFactory.getLogger(JobCompletionNotificationListener.class);

    @Override
    public void afterJob(JobExecution jobExecution) {

        SingletonExitCode exitCode = SingletonExitCode.getInstance();

       if(jobExecution.getStatus() == BatchStatus.COMPLETED)
       {
           logger.info("Exit with code " + ExitCode.NORMAL_END_OF_EXECUTION);
           exitCode.setExitCode(ExitCode.NORMAL_END_OF_EXECUTION);
       }
       else {
           logger.info("Exit with code " + ExitCode.ABNORMAL_END_OF_EXECUTION_WARNING);
           exitCode.setExitCode(ExitCode.ABNORMAL_END_OF_EXECUTION_WARNING);
       }
    }
}

但是我不强迫应用程序以System.exit()退出此类。我已经实现了一个像这样的简单单例:

public class SingletonExitCode {

    public ExitCode exitCode = ExitCode.ABNORMAL_END_OF_EXECUTION_WARNING; // Default code 3
    private static SingletonExitCode instance = new SingletonExitCode();

    private SingletonExitCode() {}

    public static SingletonExitCode getInstance() {
        return instance;
    }

    public void setExitCode(ExitCode exitCode) {
        this.exitCode = exitCode;
    }
}

并且我在关闭Spring上下文后从我的单例中请求ExitCode

@SpringBootApplication
@EnableBatchProcessing
@Import(CoreCommonsAppComponent.class)
public class Application {
    // a lot of nice things

    public static void main(String... args) throws Exception{
        ApplicationContext context = SpringApplication.run(Application.class, args);
        logger.info("================================================");
        SpringApplication.exit(context);
        System.exit(SingletonExitCode.getInstance().exitCode.getCode());
    }
}

之所以这样做,是因为如果我们直接从JobCompletionNotificationListener类退出,则会错过日志中的重要一行:

  

作业:[FlowJob:[name = writeErrorFromFile]]使用以下参数完成:[{-input.xml.file = c:/temp/unit-test-error.xml,-spring.batch.job.names = writeErrorFromFile,run.id = 15,input.xml.file = c:/temp/unit-test-error.xml}]和以下状态:[FAILED]

似乎Spring上下文没有正确关闭。

答案 1 :(得分:1)

尽管Sprint-Batch的作业处于退出状态(即COMPLETED或FAILED),Java进程仍将成功完成(并且您将获得进程退出代码为0)。

如果您想为Java进程自定义退出代码,以便可以在任何脚本或其他地方使用它,则可以使用JobExecutionListener

您可以在afterJob()中检查作业的exitStatus,并使用所需的退出代码(即FAILURE为4)退出Java进程

JobExecutionListener示例

public class InterceptingExitStatus implements JobExecutionListener{

    @Override
    public void beforeJob(JobExecution jobExecution) {
    }

    @Override
    public void afterJob(JobExecution jobExecution) {
        ExitStatus exitStatus = jobExecution.getExitStatus() ;

        if(exitStatus == ExitStatus.COMPLETED ){
            System.exit(0);
        }

        if(exitStatus == ExitStatus.FAILED ){
            System.exit(4);
        }
    }

}

这是您可以在xml文件中配置作业侦听器的方式-

<job id="job">
....
....

    <listeners>
        <listener ref="interceptingExitStatus "/>
    </listeners>
</job>

答案 2 :(得分:0)

Spring Boot和Sring Batch已经为此提供了内部解决方案,您只需要多一行代码即可:

System.exit(SpringApplication.exit(applicationContext));

这里是另一个示例:

public class BatchApplication {

    public static void main(String[] args) {
        ApplicationContext applicationContext = SpringApplication.run(BatchApplication.class, args);
        System.exit(SpringApplication.exit(applicationContext));
    }

}

编辑:如果您想知道它是如何工作的,请检查此类:org.springframework.boot.autoconfigure.batch.JobExecutionExitCodeGenerator