【发布时间】:2018-07-20 08:27:34
【问题描述】:
我正在制作一个带有 tasklet 和处理器的 Spring Batch 应用程序。 在处理器中我抛出异常,我的需要是根据我抛出的异常来 System.exit() 应用程序。
但我不知道该怎么做。
感谢您的回复
【问题讨论】:
标签: java spring spring-boot spring-batch
我正在制作一个带有 tasklet 和处理器的 Spring Batch 应用程序。 在处理器中我抛出异常,我的需要是根据我抛出的异常来 System.exit() 应用程序。
但我不知道该怎么做。
感谢您的回复
【问题讨论】:
标签: java spring spring-boot spring-batch
我的需要是根据我抛出的异常System.exit()应用程序
我不建议调用 System.exit 来终止您的应用程序,因为这会在没有正常关闭进程和清理资源的情况下终止您的工作。
如果您使用CommandLineJobRunner,您可以提供自定义ExitCodeMapper。见这里:https://docs.spring.io/spring-batch/4.0.x/reference/html/job.html#exitCodes
如果使用Spring Boot,需要调用System.exit,返回值为SpringApplication。您可以在此处找到示例:https://github.com/spring-projects/spring-boot/blob/master/spring-boot-samples/spring-boot-sample-batch/src/main/java/sample/batch/SampleBatchApplication.java#L67,更多详细信息请参见此处的参考文档:https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-application-exit
现在为了能够在处理器发生异常时自定义作业的退出代码,您需要:
ExitCodeGenerator,通过Spring Boot发送的JobExectutionEvent获取作业执行权限并自定义退出代码这是一个例子:
@Configuration
@EnableBatchProcessing
public class MyJob {
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;
@Bean
public Step step() {
return steps.get("step")
.<Integer, Integer>chunk(2)
.reader(new ListItemReader<>(Arrays.asList(1, 2, 3, 4)))
.processor(new ItemProcessor<Integer, Integer>() {
private StepExecution stepExecution;
@BeforeStep
public void beforeStep(StepExecution stepExecution) {
this.stepExecution = stepExecution;
}
@Override
public Integer process(Integer item) {
if (item.equals(3)) {
stepExecution.getJobExecution().getExecutionContext().put("failure", "item not accepted");
throw new IllegalArgumentException("3 is not accepted");
}
return item;
}
})
.writer(items -> {
for (Integer item : items) {
System.out.println("item = " + item);
}
})
.build();
}
@Bean
public Job job() {
return jobs.get("job")
.start(step())
.listener(new JobExecutionListenerSupport() {
@Override
public void afterJob(JobExecution jobExecution) {
String failure = jobExecution.getExecutionContext().getString("failure");
if (failure != null && failure.equalsIgnoreCase("item not accepted")) {
jobExecution.setExitStatus(new ExitStatus("Not Accepted"));
}
}
})
.build();
}
@Bean
public ExitCodeGenerator exitCodeGenerator () {
return new MyExitCodeGenerator();
}
static class MyExitCodeGenerator implements ExitCodeGenerator, ApplicationListener<JobExecutionEvent> {
private JobExecution jobExecution;
@Override
public int getExitCode() {
if (jobExecution.getExitStatus().getExitCode().equalsIgnoreCase("Not Accepted")) {
return 42;
}
return 0;
}
@Override
public void onApplicationEvent(JobExecutionEvent jobExecutionEvent) {
this.jobExecution = jobExecutionEvent.getJobExecution();
}
}
}
如果你运行这个:
@SpringBootApplication
public class DemoExitCodeApplication {
public static void main(String[] args) {
System.exit(
SpringApplication.exit(
SpringApplication.run(DemoExitCodeApplication.class, args)
)
);
}
}
JVM的退出码是42,这是处理器抛出异常时设置的。
【讨论】:
您可以在article 中找到一个很好的解释。一种方法是提供 ExitCodeExceptionMapper bean 以将异常映射到某些特定的退出代码:
@Bean
ExitCodeExceptionMapper exceptionMapper() {
return exception -> {
if (exception.getCause() instanceof NumberFormatException) {
return 80;
}
return 1;
};
}
更新
这个小例子应该很清楚:
@SpringBootApplication
public class DemoApplication implements CommandLineRunner {
@Bean
ExitCodeExceptionMapper exitCodeExceptionMapper() {
return exception -> {
if (exception.getCause() instanceof MyException) {
return 10;
}
return 1;
};
}
public static void main(String[] args) {
System.exit(SpringApplication
.exit(SpringApplication.run(DemoApplication.class, args)));
}
@Override
public void run(String... args) throws Exception {
throw new MyException();
}
private class MyException extends RuntimeException {}
}
然后我执行以下命令来运行应用程序:
mvn package
java -jar target/demo-1.0.0-SNAPSHOT.jar
在此命令之后,我可以使用以下命令检查退出代码:
echo Exit Code is %errorlevel%
然后它返回:
Exit Code is 10
【讨论】: