Spring Batch Batch (8) - JobLauncher and JobOperator


After successfully created a job, Spring Batch default boot configuration in the project execution time job. Often in the normal course of business processes, we need to manually or timer to trigger job, so here they introduced jobLauncher, jobOperator two actuators.

JobLauncher job scheduling


Start a job

Run a batch job has at least two requirements: a JobLauncher and one to run the job. They all contain the same or different context.

Spring Boot default to start automatically configured to support a good Job, we can configure items spring.batch.job.enabled = false to disable the Spring container automatically start Job.

Spring Launch API its core is JobLauncher interface. JobLauncher requires two parameters: Job, JobParameters.

JobLauncher interfaces:

public interface JobLauncher {  
    public JobExecution run(Job job, JobParameters jobParameters) throws (…);  
}  


Under normal circumstances, when we call Job by scheduler from the command line to start the job, will be a JVM initialization for each job, each job will have its own JobLauncher, the whole process is as follows:

file


From HttpRequest web container to start the job, usually just start job asynchronously with a JobLauncher, http request will call this JobLauncher to start the job they need. Examples of job started by the web:

file

The front index.html

<input type="text" id="msg">
<button onclick="runJob1()">Run Job 1</button>

<script type="text/javascript">
	var baseurl="http://localhost:8080";
	var xhttp=new XMLHttpRequest();
	
	function runJob1(){
		var msg = document.getElementById('msg').value;
		var url = baseurl + '/job/' +msg;
		xhttp.open('GET',url,true);
		xhttp.send();
		
		xhttp.onreadystatechange = function(){
			if(this.readyState == 4 && this.status ==200){
				console.log('Job status: '+this.responseText);
			}
		}
	}
	
</script>

JobLauncherController

@Controller
public class JobLauncherController {
    @Autowired
    JobLauncher jobLauncher;
    @Autowired
    JobLauncherDemoJob jobLauncherDemoJob;
    @RequestMapping("/job/{msg}")
    public void handle(@PathVariable String msg) throws Exception{
			// 把接收到的参数传给任务
			JobParameters parameters = new JobParametersBuilder().addString("msg",msg).toJobParameters();
			
			jobLauncher.run(jobLauncherDemoJob, parameters);
        return "JobLauncher success.";
    }
}

jobLauncher `` `@Bean public JobLauncher jobLauncher () {SimpleJobLauncher jobLauncher = new SimpleJobLauncher (); jobLauncher.setJobRepository (jobRepository ()); jobLauncher.setTaskExecutor (new SimpleAsyncTaskExecutor ()); // convert asynchronous task jobLauncher.afterPropertiesSet () ; return jobLauncher;} `` `

JobLauncherDemo

public class JobLauncherDemo implements StepExecutionListener{

    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    @Autowired
	private Map<String,JobParameters> parameters;
	
    @Bean
    public Job jobLauncherDemoJob() {
        return jobBuilderFactory.get("jobLauncherDemoJob")
				.listener(this)
                .start(jobLauncherDemoStep())
                .build();
    }
		
	@Bean
    public Step jobLauncherDemoStep() {
        return stepBuilderFactory.get("jobLauncherDemoStep")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("jobLauncherDemoStep,msg: "+parameter.get("msg").getValue());
                        return RepeatStatus.FINISHED;
                    }
                }).build();
    }
	  
	@Override
	public void beforeStep(StepExecution stepExcution){
		parameter = stepExcution.getJobParameters().getParameters();
	}
 



operation result

file


file




Stop a job


Who needs to stop job

(1), the user may for some reason, we need to stop job of running, such as found job data corruption, or throw an exception, need to stop job of work.

(2), the developer in the process of developing the program, developers clearly know some business logic necessary to stop the job. For example, a job running time can not exceed 8 am, if more than this time need to stop the job to run, and so the situation.

At this job in running the program logic of the code only after completion of these operations, the management of the program to pay back to the spring batch of time, it will be terminated. If the middle of the business operations take a long time, the job does not stop immediately. Once returns control to the framework, it will set immediately for the current StepExecution BachStatus.STOPPED, which means stop, and then save, the last of JobExecution same operation before completion.



How to Stop job

(1), the process of running throw an exception, resulting in stopping the job.

(2), using a set StepExecution identification, the job is stopped.

The best way is to use a set StepExecution to identify and stop the running job.


a, there StepExecution Tasklet interface parameters in the process can be called.

Example:

public class ProcessItemsTasklet implements Tasklet {  
    @Override  
    public RepeatStatus execute(StepContribution contribution,  
            ChunkContext chunkContext) throws Exception {  
        if(shouldStop()) {  
            chunkContext.getStepContext().getStepExecution().setTerminateOnly();  
        }  
        processItem();  
        if(moreItemsToProcess()) {  
            return RepeatStatus.CONTINUABLE;  
        } else {  
            return RepeatStatus.FINISHED;  
        }  
        }  
        (...)  
}  

B, for the "block" in the step, ItemReader, ItemProcessor, and ItemWriter three interfaces, among them no StepExecution. At this point we need to use the Listener in StepExecution.

Example:

public class StopListener {  
    private StepExecution stepExecution;  
    @BeforeStep  
    public void beforeStep(StepExecution stepExecution) {  
        this.stepExecution = stepExecution;  
    }  
      
    @AfterRead  
    public void afterRead() {  
        if(stopConditionsMet()) {  
            stepExecution.setTerminateOnly();  
        }  
    }  
    (...)  
}  

The best way from the needs of the business logic, stop job, or set stepExecution.setTerminateOnly (); this job a stop sign to let the job stop running.




Give up a job


After execution of a job is performed when the FAILED state, if it is restarted, it will be restarted.

If the execution status of the task is ABANDONED, then the frame will not restart it. ABANDONED state is also adapted to perform the steps, so that they can be skipped, performed even in a task restart: If after a step marked as failed ABANDONED encountered during task execution, is skipped the step to the next step (which is determined by the exit code definition and execution steps of the task flow).

If the current system process is dead ( "kill -9" or system error), job naturally, will not run, but JobRepository is unable to detect this error, because it does not make any notification before it dies. You have to manually tell it, you know that the mission has failed to consider giving up this or that task (set its status is FAILED or ABANDONED) - This is the business logic of things, can not be automated decision.

Only not need to restart the task was set to FAILED state, or if you know the data is still valid after the restart. Spring Batch Admin has a range of tools JobService, to cancel the ongoing task execution.




Failure of a job


Failure of the job can be restarted because of its status is FAILED, if step2 fails, it returns a return code EARLY TERMINATION, step3 will not be executed. Otherwise continue step3
<step id="step1" parent="s1" next="step2">

<step id="step2" parent="s2">
    <fail on="FAILED" exit-code="EARLY TERMINATION"/>
    <next on="*" to="step3"/>
</step>

<step id="step3" parent="s3">



The end of a job


Has ended job can not be restarted because its status is COMPLETED. If you fail step2, step3 is not executed, the job will COMPLETED, over. Step2 If successful, proceed to step3 down.
<step id="step1" parent="s1" next="step2">

<step id="step2" parent="s2">
    <end on="FAILED"/>
    <next on="*" to="step3"/>
</step>

<step id="step3" parent="s3">





JobOperator


A JobLauncher use a JobRepository create and run a new JobExection objects, Job and Step achieve the same JobRepository subsequently used during the job run to update the same JobExecution object.

file



These basic operations to meet the needs of a simple scene, but the case for large batch has hundreds of complex tasks and the timing of the process, the need to use a more advanced way to access metadata:

file


JobRepository provide CRUD operations of metadata, JobExplorer provided a read-only operations of metadata. However, these operations are most often used in combination with many classes of bulk operations to monitor the task and complete the task quite a bit of control functions, such as stop, restart or task summary. In the Spring Batch JobOperator interface provides these types of operations:

public interface JobOperator {
      List<Long> getExecutions(long instanceId) throws NoSuchJobInstanceException;
      List<Long> getJobInstances(String jobName, int start, int count)throws NoSuchJobException;
      Set<Long> getRunningExecutions(String jobName) throws NoSuchJobException;
      String getParameters(long executionId) throws NoSuchJobExecutionException;
      Long start(String jobName, String parameters)throws NoSuchJobException, JobInstanceAlreadyExistsException;
      Long restart(long executionId)throws JobInstanceAlreadyCompleteException, NoSuchJobExecutionException,
                                 NoSuchJobException, JobRestartException;
      Long startNextInstance(String jobName)throws NoSuchJobException, JobParametersNotFoundException, JobRestartException,
                                 JobExecutionAlreadyRunningException, JobInstanceAlreadyCompleteException;
      boolean stop(long executionId)throws NoSuchJobExecutionException, JobExecutionNotRunningException;
      String getSummary(long executionId) throws NoSuchJobExecutionException;Map<Long, String> getStepExecutionSummaries(long executionId)
                                 throws NoSuchJobExecutionException;
      Set<String> getJobNames();
}

The most common role JobOperator than stop a Job:

Set<Long> executions = jobOperator.getRunningExecutions("sampleJob");
jobOperator.stop(executions.iterator().next());

Close not happen immediately, because there is no way to enforce a task immediately stopped, especially when the task to a developer's code segment, the frame at the moment is powerless, such as a business logic processing. Once returns control to the framework, it will set immediately for the current StepExecution BachStatus.STOPPED, which means stop, and then save, the last of JobExecution same operation before completion.

Here we go call jobOperator through web API interface, passing through the interface parameters job. Call Job is based in the creation of job, Bean name to specify.

Example:

@Controller
public class JobOperatorController {
	@Autowired
    private JobOperatorDemo jobOperatorDemo;

	//不需要注入Job对象
    //@Autowired
    //JobLauncherDemoJob jobLauncherDemoJob;
		
    @RequestMapping("/job/{msg}")
    public void handle(@PathVariable String msg) throws Exception{
			// 把接收到的参数传给任务
			System.out.println("Request to run job2 with param: " + job2param);
 
        jobOperatorDemo.start("jobOperatorDemoJob","msg="+msg);
 
        return "JobOperator success.";
    }
}

``` public class JobOperatorDemo implements StepExecutionListener,ApplicationContextAware{
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private Map<String,JobParameters> parameters;

@Autowired
private JobRepository jobRepository;

@Autowired
private JobExplorer jobExplorer;

@Autowired
private JobRegistry jobRegistry;

@Autowired
private JobLauncher jobLauncher;
	
	pricate ApplicationContext context;
	
	 
@Bean
public JobRepositoryBeanPostProcessor jobRegistrar() throws Exception{
	JobRepositoryBeanPostProcessor postProcessor = new JobRepositoryBeanPostProcessor;
	
	postProcessor.setJobRegistry(jobRegistry);
	postProcessor.setBeanFactory(context.getAutowireCapableBeanFactory());
	postProcessor.afterPropertiesSet();
	
	return postProcessor;
}
	
@Bean
public JobOperator jobOperator(){
    SimpleJobOperator operator = new SimpleJobOperator();

    operator.setJobLauncher(jobLauncher);
			// 参数转换
    operator.setJobParametersConverter(new DefaultJobParametersConverter());
			// 持久化方式
    operator.setJobRepository(jobRepository);
			// 任务相关信息
    operator.setJobExplorer(jobExplorer);
			// 注册:任务名字符串和任务对象关联
    operator.setJobRegistry(jobRegistry);
    return operator;
}

@Bean
public Job jobOperatorDemo() {
    return jobBuilderFactory.get("jobOperatorDemo")
			.listener(this)
            .start(jobOperatorDemoStep())
            .build();
}
	
@Bean
public Step jobOperatorDemoStep() {
    return stepBuilderFactory.get("jobOperatorDemoStep")
            .tasklet(new Tasklet() {
                @Override
                public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                    System.out.println("jobOperatorDemoStep,msg: "+parameter.get("msg").getValue());
                    return RepeatStatus.FINISHED;
                }
            }).build();
}
  
@Override
public void beforeStep(StepExecution stepExcution){
	parameter = stepExcution.getJobParameters().getParameters();
}



@Override
public void setApplicationContext(ApplicationContext applicationContext){
	this.context = applicationContext;
}


<br/><br/>


<br/><br/>
 
 
 参考:
 
 https://blog.csdn.net/github_36849773/article/details/66968461
 
 https://www.iteye.com/blog/kanpiaoxue-1771208
 
 https://www.cnblogs.com/nizuimeiabc1/p/9409492.html
 
 https://blog.csdn.net/kangkanglou/article/details/82627799
 
 https://blog.csdn.net/wuzhiwei549/article/details/85394406
He published 187 original articles · won praise 79 · views 160 000 +

Guess you like

Origin blog.csdn.net/weixin_38004638/article/details/104765045