一、About
Spring Batch是什么能干什么,網上一搜就有,但是就是沒有入門實例,能找到的例子也都是2.0的,看文檔都是英文無從下手~~~,使用當前最新的版本整合網絡上找到的例子。
關於基礎不熟悉的,推薦讀一下Spring Batch 批處理框架這本書,雖然講的是2.0但基本概念沒變。
1.1 How Spring Batch works?
一個Job有1個或多個Step組成,Step有讀、處理、寫三部分操作組成;通過JobLauncher啟動Job,啟動時從JobRepository獲取Job Execution;當前運行的Job及Step的結果及狀態保存在JobRepository中。
二、Begin
下面舉個小例子,就是這篇文章中的例子,下面的這個例子版本是最新的:
- spring-boot:2.0.1.RELEASE
- spring-batch-4.0.1.RELEASE(Spring-Boot 2.0.1就是依賴的此版本)
下面這個例子實現的是:從變量中讀取3個字符串全轉化大寫並輸出到控制台,加了一個監聽,當任務完成時輸出一個字符串到控制台,通過web端來調用。
下面是項目的目錄結構:
2.1 pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javainuse</groupId>
<artifactId>springboot-batch</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>SpringBatch</name>
<description>Spring Batch-Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2 Item Reader
讀取:從數組中讀取3個字符串
package com.javainuse.step;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.NonTransientResourceException;
import org.springframework.batch.item.ParseException;
import org.springframework.batch.item.UnexpectedInputException;
public class Reader implements ItemReader<String> {
private String[] messages = { "javainuse.com",
"Welcome to Spring Batch Example",
"We use H2 Database for this example" };
private int count = 0;
@Override
public String read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
if (count < messages.length) {
return messages[count++];
} else {
count = 0;
}
return null;
}
}
2.3 Item Processor
處理:將字符串轉為大寫
package com.javainuse.step;
import org.springframework.batch.item.ItemProcessor;
public class Processor implements ItemProcessor<String, String> {
@Override
public String process(String data) throws Exception {
return data.toUpperCase();
}
}
2.4 Item Writer
輸出:把轉為大寫的字符串輸出到控制台
package com.javainuse.step;
import java.util.List;
import org.springframework.batch.item.ItemWriter;
public class Writer implements ItemWriter<String> {
@Override
public void write(List<? extends String> messages) throws Exception {
for (String msg : messages) {
System.out.println("Writing the data " + msg);
}
}
}
2.5 Listener
監聽:任務成功完成后往控制台輸出一行字符串
package com.javainuse.listener;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.listener.JobExecutionListenerSupport;
public class JobCompletionListener extends JobExecutionListenerSupport {
@Override
public void afterJob(JobExecution jobExecution) {
if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
System.out.println("BATCH JOB COMPLETED SUCCESSFULLY");
}
}
}
2.6 Config
Spring Boot配置:
package com.javainuse.config;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.javainuse.listener.JobCompletionListener;
import com.javainuse.step.Processor;
import com.javainuse.step.Reader;
import com.javainuse.step.Writer;
@Configuration
public class BatchConfig {
@Autowired
public JobBuilderFactory jobBuilderFactory;
@Autowired
public StepBuilderFactory stepBuilderFactory;
@Bean
public Job processJob() {
return jobBuilderFactory.get("processJob")
.incrementer(new RunIdIncrementer()).listener(listener())
.flow(orderStep1()).end().build();
}
@Bean
public Step orderStep1() {
return stepBuilderFactory.get("orderStep1").<String, String> chunk(1)
.reader(new Reader()).processor(new Processor())
.writer(new Writer()).build();
}
@Bean
public JobExecutionListener listener() {
return new JobCompletionListener();
}
}
2.7 Controller
控制器:配置web路由,訪問/invokejob來調用任務
package com.javainuse.controller;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class JobInvokerController {
@Autowired
JobLauncher jobLauncher;
@Autowired
Job processJob;
@RequestMapping("/invokejob")
public String handle() throws Exception {
JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis())
.toJobParameters();
jobLauncher.run(processJob, jobParameters);
return "Batch job has been invoked";
}
}
2.8 application.properties
配置:Spring Batch在加載的時候job默認都會執行,把spring.batch.job.enabled
置為false,即把job設置成不可用,應用便會根據jobLauncher.run來執行。下面2行是數據庫的配置,不配置也可以,使用的嵌入式數據庫h2
spring.batch.job.enabled=false
spring.datasource.url=jdbc:h2:file:./DB
spring.jpa.properties.hibernate.hbm2ddl.auto=update
2.9 Application
Spring Boot入口類:加注解@EnableBatchProcessing
package com.javainuse;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableBatchProcessing
public class SpringBatchApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBatchApplication.class, args);
}
}
三、Run
啟動這個Spring Boot項目,訪問下面這個路徑,會有如下輸出
http://localhost:8080/invokejob
然后控制台會有如下輸出:
我們可以使用H2-console來查看H2數據庫,訪問如下地址 http://localhost:8080/h2-console , 選擇如下數據庫,輸入JDBC URL:jdbc:h2:file:./DB,這是上文配置的,不用輸入密碼,直接點擊Connect就可以了。
連上后顯示如下:
左側那些表就是Spring Batch自動創建的,至於每個表都是什么意思,可參考下面的那本書,這些建表的腳本存在於哪呢?可在spring-batch-core-xxx.jar包下的org.springframework.batch.core包下找到
查看batch-h2.properties可以看到相關的默認配置: