前面介绍了如何使用 Job,那么我们能否监听 Job 执行前后呢?答案是肯定的,Spring Batch4 提供了一个 JobExecutionListener 接口,该接口用来监听批处理作业(Job)的执行状态,如执行开始、执行结束,这就能让你在作业执行的前后阶段插入自定义逻辑。如下图:
注意,JobExecutionListener 接口可监听作业的开始和结束,接口中定义了两个核心方法:
beforeJob(JobExecution jobExecution):在作业启动之前调用,可用于初始化资源或者进行参数验证。
afterJob(JobExecution jobExecution):作业结束后调用,不管作业是正常完成、失败还是被中断,此方法都会被触发,适合用来释放资源或者记录审计信息。
JobExecutionListener 接口定义如下:
package org.springframework.batch.core; /** * 在 {@link Job} 的生命周期中的特定点提供回调。 * 如果实现者小心确保线程安全,或者为每个作业使用一个监听器实例 *(假设作业实例本身不会被多个线程使用),则实现可以是有状态的。 * * @author Dave Syer * */ public interface JobExecutionListener { /** * 作业执行前的回调。 * * @param jobExecution the current {@link JobExecution} */ void beforeJob(JobExecution jobExecution); /** * 作业完成后的回调。在成功和失败的执行之后都会调用。 * 要针对特定状态执行逻辑,请使用“if (jobExecution.getStatus() == BatchStatus.X)”。 * * @param jobExecution the current {@link JobExecution} */ void afterJob(JobExecution jobExecution); }
下面通过一个简单例子介绍如何使用 JobExecutionListener 监听 Job 的生命周期。
创建 MyJobExecutionListener 类,实现 JobExecutionListener 接口。分别在 beforeJob() 和 afterJob() 方法中打印 Job 名称。代码如下:
package com.hxstrive.spring_batch.listenerDemo.listener; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.JobExecutionListener; /** * JobExecutionListener 监听器:Job执行前后监听器 * @author hxstrive.com */ public class MyJobExecutionListener implements JobExecutionListener { @Override public void beforeJob(JobExecution jobExecution) { System.out.println("MyJobExecutionListener beforeJob :: " + jobExecution.getJobInstance().getJobName()); } @Override public void afterJob(JobExecution jobExecution) { System.out.println("MyJobExecutionListener afterJob :: " + jobExecution.getJobInstance().getJobName()); } }
创建 BatchConfig 配置类,创建一个 Job,然后设置自定义的监听器 MyJobExecutionListener。代码如下:
package com.hxstrive.spring_batch.listenerJobDemo.config; import com.hxstrive.spring_batch.listenerJobDemo.listener.MyJobExecutionListener; import org.springframework.batch.core.Job; import org.springframework.batch.core.Step; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Spring Batch 配置类 * @author hxstrive.com */ @Configuration public class BatchConfig { // 用于创建和配置 Job 对象的工厂类 @Autowired private JobBuilderFactory jobBuilderFactory; // 用于创建和配置 Step 对象的工厂类 @Autowired private StepBuilderFactory stepBuilderFactory; // 创建 Step 对象 @Bean public Step listenerJobDemoStep1() { return stepBuilderFactory.get("listenerJobDemoStep1") .tasklet(new Tasklet() { @Override public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception { System.out.println(Thread.currentThread().getName() + " listenerJobDemoStep1"); return RepeatStatus.FINISHED; // 返回 FINISHED 表明任务执行结束 } }).build(); } // 创建 Job 任务 @Bean public Job listenerJobDemoJob() { return jobBuilderFactory.get("listenerJobDemo" + System.currentTimeMillis()) .listener(new MyJobExecutionListener()) // 添加 Job 执行监听器 .start(listenerJobDemoStep1()) .build(); } }
上述代码中,使用 listener(new MyJobExecutionListener()) 代码为 Job 添加监听器。
运行应用程序,查看输出日志:
注意,在 JobExecutionListener 接口的 beforeJob() 或 afterJob() 方法中,可以通过参数 JobExecution 的 getStatus() 方法获取 Job 执行状态,状态为 BatchStatus 枚举对象。
BatchStatus 用于表示批处理作业(Job)或步骤(Step)的执行状态,这个枚举类定义了作业生命周期中可能的各种状态,帮助你跟踪和管理批处理任务的执行情况。
BatchStatus 枚举类包含以下状态:
COMPLETED:作业或步骤已成功完成。所有任务都按预期执行,没有错误发生。
STARTING:作业或步骤正在启动过程中,尚未完全开始执行。
STARTED:作业或步骤已成功启动,正在执行中。
STOPPING:作业或步骤正在停止过程中,但尚未完全停止。
STOPPED:作业或步骤已被成功停止,通常是通过外部干预(如手动停止)。
FAILED:作业或步骤执行失败,可能是由于异常或错误导致的。
ABANDONED:作业或步骤已被放弃,通常在处理失败的作业时,需要跳过某些已处理的项。
UNKNOWN:状态未知,通常表示出现了意外情况或状态无法确定。
状态的简单用法如下:
@Override public void afterJob(JobExecution jobExecution) { System.out.println("MyJobExecutionListener afterJob :: " + jobExecution.getJobInstance().getJobName()); final BatchStatus status = jobExecution.getStatus(); if(status.equals(BatchStatus.COMPLETED)) { // 作业执行成功 System.out.println("Job completed successfully"); } else if(status.equals(BatchStatus.FAILED)) { // 作业执行失败 System.err.println("Job failed with exceptions: " + jobExecution.getAllFailureExceptions()); } }
作业的典型状态转换流程如下图:
BatchStatus 枚举能帮助你跟踪和管理批处理作业的执行状态。了解各种状态及其转换流程,能够更好地监控作业执行情况,并在必要时采取相应的措施(如重试失败的作业)。