1. Spring Batch的设计图
比较重要的几个domain
- Job 任务
- Step 任务里包含的步骤
- ItemReader 单个步骤里的输入(input)
- ItemProccesor input的处理
- ItemWriter 单个步骤里的输出(output)
ItemReader,ItemProccesor,ItemWriter这个类似于java 8里funtional编程
- public interface Supplier
- public interface Function<T, R>
- public interface Consumer
2. Job
Job 执行后就产生一个JobInstance,好比类和实例的关系,1个JobInstance 可以有好多个 JobExcution
2.1 JobParameter
JobParameters就是job运行的一些算入参数
例如 通过cmd运行一个endOfDay的任务,
传入的参数是schedule.date(date)=2007/05/05,这个会构成一个JobParameter
java CommandLineJobRunner io.spring.EndOfDayJobConfiguration endOfDay schedule.date(date)=2018/05/05
上面的命令说明
CommandLineJobRunner 是spring batch提供的一个具有main方法的类,接收参数如下
- io.spring.EndOfDayJobConfiguration 是一个Job的Spring 的@configuration类,里面包含了基本的Job的构成step
- endOfDay是一个Job的定义,Spring的@Bean
- schedule.date(date)=2007/05/05是参数
2.2 JobInstance 和 JobExcution的关系
下面的命令运行n次都只产生1个JobInstance
java CommandLineJobRunner io.spring.EndOfDayJobConfiguration endOfDay schedule.date(date)=2018/05/05
也就是说 JobInstance = Job + identifying JobParameters
同一个JobInstance不同次运行有不同的JobExcution,JobExcution会记录开始时间,结束时间,状态等的字段,具体的看
JobExcution包含哪些字段
2.3 spring batch的内置表来直观看上面的关系
BATCH_JOB_INSTANCE
| JOB_INST_ID | JOB_NAME |
|---|---|
| 1 | EndOfDayJob |
| 2 | EndOfDayJob |
BATCH_JOB_EXECUTION_PARAMS
| JOB_EXECUTION_ID | TYPE_CD | KEY_NAME | DATE_VAL | IDENTIFYING |
|---|---|---|---|---|
| 1 | DATE | schedule.Date | 2017-01-01 00:00:00 | true |
| 2 | DATE | schedule.Date | 2017-01-01 00:00:00 | true |
| 3 | DATE | schedule.Date | 2017-01-02 00:00:00 | true |
BATCH_JOB_EXECUTION
| JOB_EXECUTION_ID | JOB_INST_ID | START_TIME | END_TIME | STATUS |
|---|---|---|---|---|
| 1 | 1 | 2017-01-01 21:00 | 2017-01-01 21:30 | FAILED |
| 2 | 1 | 2017-01-02 21:00 | 2017-01-02 21:30 | COMPLETED |
| 3 | 2 | 2017-01-02 21:31 | 2017-01-02 22:29 | COMPLETED |
spring batch 内置表的关系图如下
3. Step
每次step触发后就会产生一个stepExecution,step不像job,是没有stepinstance的。对于stepExecution,对应的表有
-
BATCH_STEP_EXECUTION用来记录开始时间,结束时间,状态等字段记录 -
BATCH_STEP_EXECUTION_CONTEXT通过executionContext.putLong(getKey(LINES_READ_COUNT), reader.getPosition());可以表里存入一些记录
4.Sample
从一个文件中读取数据,封装成Person对象并打印
Person.txt
1,Rechard,20
2,James,30
3,Cury,28
4,Durant,26
Person.java
public class Person {
private int id;
private String name;
private int age;
//getter and setter
}
Batch的@Configuration
Job里配置一个Step
- step里的reader 从文件Person.txt中读数据,每一行代表 Person的信息,封装成Person对象
- step里的Processor
将Person打印出来
@Configuration
@ComponentScan("rechard.learn.springbatch.sample.simple")
@EnableBatchProcessing
public class SimpleBatchConfiguration {
@Autowired
JobBuilderFactory jobBuilders;
@Autowired
private StepBuilderFactory steps;
@Autowired
//配置1个Job,job里只有1个step
@Bean
public Job simpleJob(Step step){
return jobBuilders.get("simpleJob").start(step).build();
}
//step 里的reader和writer
@Bean
protected Step step(ItemReader<String> reader,
ItemWriter<Person> writer) {
return steps.get("step1")
.<String, Person> chunk(10)
.reader(reader)
.writer(writer)
.build();
}
//reader 使用sprinb batch内置的FlatFileItemReader,读取1行并封装成为1个Person 对象
@Bean
protected ItemReader<String> reader(){
FlatFileItemReader reader=new FlatFileItemReader();
FileInputStream fis = null;
try {
fis = new FileInputStream(new File("E:\\person.txt"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
reader.setResource( new InputStreamResource(fis));
reader.setLineMapper((line,number)->{
String[] str = line.split(",");
Person p = new Person();
p.setId(Integer.parseInt(str[0]));
p.setName(str[1]);
p.setAge(Integer.parseInt(str[2]));
return p;
});
return reader;
}
//reader 则简单的打印出来,这里是ItemWriterAdapter,这个类主要是设置一个代理类来帮助打印,代理类就是真实的处理Person逻辑的类PersonProcessor
@Bean
protected ItemWriter<Person> writer(){
ItemWriterAdapter<Person> adapter = new ItemWriterAdapter();
adapter.setTargetMethod("print");
adapter.setTargetObject(new PersonProcessor());
return adapter;
}
}
PersonProcessor
public class PersonProcessor {
public void print(Person p){
System.out.println(p.toString());
}
}
main的启动类
public class SimpleDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(SimpleBatchConfiguration.class);
ctx.refresh();
JobLauncher launcher = (JobLauncher)ctx.getBean("jobLauncher");
JobParameters parameters = new JobParameters();
try {
launcher.run((Job)ctx.getBean("simpleJob"),parameters);
} catch (Exception e) {
e.printStackTrace();
}
}
}
打印出来的结果
Person{id=1, name='Rechard', age=20}
Person{id=2, name='James', age=30}
Person{id=3, name='Cury', age=28}
Person{id=4, name='Durant', age=26}