您的位置:首页 > 编程语言 > Java开发

spring batch job 详细配置以及多个job时如何根据参数执行指定job

2017-03-22 12:06 1996 查看
 spring batch写批处理程序时,往往会不止一个job的场景,并且需要根据实际需要来选择执行指定的job,比如:java -jar xxx.jar -参数,根据参数的不同来执行不同的job。

下面以spring boot为基础的spring batch程序为例,讲述多个job时的相关配置。

1、因为本文重点是介绍多个job时怎么选择性执行,先写两个job的简单配置:

第一个Job的配置,根据需要也可配置多个step:

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.*;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.batch.core.launch.support.RunIdIncrementer;

import java.util.List;
import java.util.Map;

@Configuration
@EnableBatchProcessing
public class JobOneConfiguration {

@Autowired
private JobBuilderFactory jobBuilderFactory;

@Autowired
private StepBuilderFactory stepBuilderFactory;

//job
@Bean
public Job jobOne() {
return jobBuilderFactory.get("jobOne")
.incrementer(new RunIdIncrementer())
.start(step1())
.build();
}

@Bean
public JdbcCursorItemReader<Map<String, String>> reader() {
JdbcCursorItemReader<Map<String, String>> reader = new JdbcCursorItemReader<>();
//reader逻辑根据实际需要写,先不举例
return reader;
}

public ItemProcessor<Map<String, String>, String> tableProcessor() {
return new ItemProcessor<Map<String, String>, String>() {
@Override
public String process(Map<String, String> map) throws Exception {
String insertSql = "";
//process逻辑根据实际需要写,先不举例
return insertSql;
}
};
}

@Bean
public ItemWriter<String> writer() {
return new ItemWriter<String>() {
@Override
public void write(List<? extends String> list) throws Exception {
//writer逻辑根据实际需要写,先不举例
}
};
}

//step
@Bean
@JobScope
public Step step1() {
return stepBuilderFactory.get("step1")
.<Map<String, String>, String>chunk(100)
.reader(reader())
.processor(tableProcessor())
.writer(writer())
.build();
}
}

第二个job的配置也类似:

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.*;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.batch.core.launch.support.RunIdIncrementer;

import java.util.List;
import java.util.Map;

@Configuration
@EnableBatchProcessing
public class JobTwoConfiguration {

@Autowired
private JobBuilderFactory job;

@Autowired
private StepBuilderFactory step;

//job
@Bean
public Job jobTwo() {
return job.get("jobTwo")
.incrementer(new RunIdIncrementer())
.start(step1())
.build();
}

@Bean
public JdbcCursorItemReader<Map<String, String>> reader2() {
JdbcCursorItemReader<Map<String, String>> reader = new JdbcCursorItemReader<>();
//reader逻辑根据实际需要写,先不举例
return reader;
}

public ItemProcessor<Map<String, String>, String> tableProcessor2() {
return new ItemProcessor<Map<String, String>, String>() {
@Override
public String process(Map<String, String> map) throws Exception {
String insertSql = "";
//process逻辑根据实际需要写,先不举例
return insertSql;
}
};
}

@Bean
public ItemWriter<String> writer2() {
return new ItemWriter<String>() {
@Override
public void write(List<? extends String> list) throws Exception {
//writer逻辑根据实际需要写,先不举例
}
};
}

//step
@Bean
@JobScope
public Step step2() {
return step.get("step2")
.<Map<String, String>, String>chunk(100)
.reader(reader2())
.processor(tableProcessor2())
.writer(writer2())
.build();
}
}


2、这个比较重要,把刚刚两个job类配置到这个类中,提供get方法返回,供后面ctx.getBean()来选择:

import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.support.ApplicationContextFactory;
import org.springframework.batch.core.configuration.support.GenericApplicationContextFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableBatchProcessing(modular=true)
public class JobConfiguration {

@Bean
public ApplicationContextFactory oneJob(){
return new GenericApplicationContextFactory(JobOneConfiguration.class);
}

@Bean
public ApplicationContextFactory twoJob(){
return new GenericApplicationContextFactory(JobTwoConfiguration.class);
}
}


3、main函数代码,根据args来判断并选择job来执行:

import org.springframework.batch.core.*;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.BeansException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.ConfigurableApplicationContext;

import java.io.IOException;
import java.util.Date;

@SpringBootApplication
@ComponentScan
@EnableAutoConfiguration
public class BatchApplication {

public static void main(String[] args) throws BeansException, JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException, InterruptedException, IOException {
boolean oneJob = false;
boolean twoJob = false;

SpringApplication application = new SpringApplication(BatchApplication.class);
application.setWebEnvironment(false);
ConfigurableApplicationContext ctx = application.run(args);
JobLauncher jobLauncher = ctx.getBean(JobLauncher.class);

//无参数时,都执行
if (args.length == 0) {
oneJob = true;
twoJob = true;
} else {
for (String arg : args) {
if (arg.toLowerCase().equals("?")) {
System.out.println("Usage : Batch [-b] [-r]");
}
if (arg.toLowerCase().equals("-o") || arg == null) {
oneJob = true;
}
if (arg.toLowerCase().equals("-t")) {
twoJob = true;
}
}
}
if (oneJob) {
JobParameters jobParameters = new JobParametersBuilder()
.addDate("date", new Date())
.toJobParameters();
jobLauncher.run(ctx.getBean("jobOne", Job.class), jobParameters)
//jobOne名称必须和JobOneConfiguration中配置的@bean Job 的方法名一致,后面jobTwo也是一样。
}
if (twoJob) {
JobParameters jobParameters = new JobParametersBuilder()
.addDate("date", new Date())
.toJobParameters();
jobLauncher.run(ctx.getBean("jobTwo", Job.class), jobParameters);
}

System.exit(0);

}
}

以上代码完成之后,发现启动时,不管参数是-o还是-t,都会先把jobOne和jobTwo执行一遍。这是因为spring batch在加载的时候job默认都会执行。解决方法:在application.properties中增加配置:

spring.batch.job.enabled=false

把job都设置成不可用,程序便会根据jobLauncher.run来执行job。

--------------------------------------------------------------------------------------------------------------------------------------------------------

关于spring batch更细节和更多的配置说明,会持续更新~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐