├── .gitignore ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── github │ │ └── dylanz666 │ │ ├── App.java │ │ ├── config │ │ ├── BatchConfig.java │ │ └── SpringScheduledConfig.java │ │ ├── controller │ │ └── BatchController.java │ │ └── service │ │ ├── ItemProcessorService.java │ │ ├── ItemProcessorService2.java │ │ ├── ItemReaderService.java │ │ ├── ItemReaderService2.java │ │ ├── ItemWriterService.java │ │ └── JobListener.java └── resources │ ├── application.properties │ └── logback-spring.xml └── test └── java └── com └── github └── dylanz666 └── AppTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # spring-batch-demo 2 | spring-batch-demo 3 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.github.dylanz666 5 | spring-boot-batch-demo 6 | jar 7 | 1.0-SNAPSHOT 8 | spring-boot-batch-demo 9 | https://github.com/dylanz666 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-parent 14 | 2.3.1.RELEASE 15 | 16 | 17 | 18 | 19 | 20 | alimaven 21 | aliyun maven 22 | http://maven.aliyun.com/nexus/content/repositories/central/ 23 | 24 | 25 | 26 | 27 | 28 | junit 29 | junit 30 | 3.8.1 31 | test 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-web 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-batch 40 | 41 | 42 | com.h2database 43 | h2 44 | runtime 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | 50 | 51 | org.projectlombok 52 | lombok 53 | 1.18.12 54 | provided 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/main/java/com/github/dylanz666/App.java: -------------------------------------------------------------------------------- 1 | package com.github.dylanz666; 2 | 3 | import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | /** 8 | * @author : dylanz 9 | * @since : 08/25/2020 10 | */ 11 | @SpringBootApplication 12 | @EnableBatchProcessing 13 | //@EnableScheduling 14 | public class App { 15 | public static void main(String[] args) { 16 | SpringApplication.run(App.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/dylanz666/config/BatchConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.dylanz666.config; 2 | 3 | import com.github.dylanz666.service.*; 4 | import org.springframework.batch.core.Job; 5 | import org.springframework.batch.core.JobExecutionListener; 6 | import org.springframework.batch.core.Step; 7 | import org.springframework.batch.core.configuration.annotation.JobBuilderFactory; 8 | import org.springframework.batch.core.configuration.annotation.StepBuilderFactory; 9 | import org.springframework.batch.core.launch.support.RunIdIncrementer; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.context.annotation.Bean; 12 | import org.springframework.context.annotation.Configuration; 13 | 14 | /** 15 | * @author : dylanz 16 | * @since : 08/25/2020 17 | */ 18 | @Configuration 19 | public class BatchConfig { 20 | @Autowired 21 | private JobBuilderFactory jobBuilderFactory; 22 | @Autowired 23 | private StepBuilderFactory stepBuilderFactory; 24 | @Autowired 25 | private ItemReaderService itemReaderService; 26 | @Autowired 27 | private ItemReaderService2 itemReaderService2; 28 | @Autowired 29 | private ItemProcessorService itemProcessorService; 30 | @Autowired 31 | private ItemProcessorService2 itemProcessorService2; 32 | @Autowired 33 | private ItemWriterService itemWriterService; 34 | @Autowired 35 | private JobListener jobListener; 36 | 37 | @Bean 38 | public Job singleStepJob() { 39 | return jobBuilderFactory.get("singleStepJob") 40 | .incrementer(new RunIdIncrementer()) 41 | .listener(listener()) 42 | .start(uppercaseStep()) 43 | .build(); 44 | } 45 | 46 | @Bean 47 | public Job multiBoundStepsJob() { 48 | return jobBuilderFactory.get("multiBoundStepsJob") 49 | .incrementer(new RunIdIncrementer()) 50 | .listener(listener()) 51 | .start(uppercaseStep()) 52 | .next(addMessageStep()) 53 | .build(); 54 | } 55 | 56 | @Bean 57 | public Step uppercaseStep() { 58 | return stepBuilderFactory.get("uppercaseStep") 59 | .chunk(1) 60 | .reader(itemReaderService) 61 | .processor(itemProcessorService) 62 | .writer(itemWriterService).build(); 63 | } 64 | 65 | @Bean 66 | public Step addMessageStep() { 67 | return stepBuilderFactory.get("addMessageStep") 68 | .chunk(1) 69 | .reader(itemReaderService2) 70 | .processor(itemProcessorService2) 71 | .writer(itemWriterService).build(); 72 | } 73 | 74 | @Bean 75 | public JobExecutionListener listener() { 76 | return jobListener; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/github/dylanz666/config/SpringScheduledConfig.java: -------------------------------------------------------------------------------- 1 | package com.github.dylanz666.config; 2 | 3 | import org.springframework.batch.core.Job; 4 | import org.springframework.batch.core.JobParameters; 5 | import org.springframework.batch.core.JobParametersBuilder; 6 | import org.springframework.batch.core.launch.JobLauncher; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.scheduling.annotation.Scheduled; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * @author : dylanz 13 | * @since : 08/25/2020 14 | */ 15 | @Component 16 | public class SpringScheduledConfig { 17 | @Autowired 18 | private Job singleStepJob; 19 | @Autowired 20 | private JobLauncher jobLauncher; 21 | 22 | @Scheduled(cron = "0/5 * * * * ?") 23 | public void demoScheduled() throws Exception { 24 | JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis()) 25 | .toJobParameters(); 26 | jobLauncher.run(singleStepJob, jobParameters); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/github/dylanz666/controller/BatchController.java: -------------------------------------------------------------------------------- 1 | package com.github.dylanz666.controller; 2 | 3 | import org.springframework.batch.core.Job; 4 | import org.springframework.batch.core.JobParameters; 5 | import org.springframework.batch.core.JobParametersBuilder; 6 | import org.springframework.batch.core.launch.JobLauncher; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | /** 12 | * @author : dylanz 13 | * @since : 08/25/2020 14 | */ 15 | @RestController 16 | public class BatchController { 17 | @Autowired 18 | private Job singleStepJob; 19 | @Autowired 20 | private Job multiBoundStepsJob; 21 | @Autowired 22 | private JobLauncher jobLauncher; 23 | 24 | @GetMapping("/job/step") 25 | public String invokeStep() throws Exception { 26 | JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis()) 27 | .toJobParameters(); 28 | jobLauncher.run(singleStepJob, jobParameters); 29 | return "The job is proceed."; 30 | } 31 | 32 | @GetMapping("/job/steps") 33 | public String invokeSteps() throws Exception { 34 | JobParameters jobParameters = new JobParametersBuilder().addLong("time", System.currentTimeMillis()) 35 | .toJobParameters(); 36 | jobLauncher.run(multiBoundStepsJob, jobParameters); 37 | return "The multi bound steps job is proceed."; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/github/dylanz666/service/ItemProcessorService.java: -------------------------------------------------------------------------------- 1 | package com.github.dylanz666.service; 2 | 3 | import org.springframework.batch.item.ItemProcessor; 4 | import org.springframework.stereotype.Service; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | /** 10 | * @author : dylanz 11 | * @since : 08/25/2020 12 | */ 13 | @Service 14 | public class ItemProcessorService implements ItemProcessor { 15 | public static String[] message; 16 | //在此处进行数据处理操作,如进行计算、逻辑处理、格式转换等,本例将数据变成全大写数据; 17 | public String process(String data) throws Exception { 18 | //存储处理过的数据,可供下一个step使用 19 | List list = new ArrayList<>(); 20 | if (message != null) { 21 | for (int i = 0; i < message.length; i++) { 22 | list.add(message[i]); 23 | } 24 | } 25 | list.add(data.toUpperCase()); 26 | message = list.toArray(new String[list.size()]); 27 | return data.toUpperCase(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/github/dylanz666/service/ItemProcessorService2.java: -------------------------------------------------------------------------------- 1 | package com.github.dylanz666.service; 2 | 3 | import org.springframework.batch.item.ItemProcessor; 4 | import org.springframework.stereotype.Service; 5 | 6 | /** 7 | * @author : dylanz 8 | * @since : 08/26/2020 9 | */ 10 | @Service 11 | public class ItemProcessorService2 implements ItemProcessor { 12 | public String process(String data) throws Exception { 13 | return data + " dylanz"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/dylanz666/service/ItemReaderService.java: -------------------------------------------------------------------------------- 1 | package com.github.dylanz666.service; 2 | 3 | import org.springframework.batch.item.ItemReader; 4 | import org.springframework.stereotype.Service; 5 | 6 | /** 7 | * @author : dylanz 8 | * @since : 08/25/2020 9 | */ 10 | @Service 11 | public class ItemReaderService implements ItemReader { 12 | //在此处进行数据读取操作,如从数据库查询、从文件中读取、从变量中读取等,本例从变量中读取; 13 | private String[] message = {"message 1", "message 2", "message 3", "message 4", "message 5"}; 14 | private int count = 0; 15 | 16 | public String read() throws Exception { 17 | if (count < message.length) { 18 | return message[count++]; 19 | } 20 | count = 0; 21 | return null; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/github/dylanz666/service/ItemReaderService2.java: -------------------------------------------------------------------------------- 1 | package com.github.dylanz666.service; 2 | 3 | import org.springframework.batch.item.ItemReader; 4 | import org.springframework.stereotype.Service; 5 | 6 | /** 7 | * @author : dylanz 8 | * @since : 08/26/2020 9 | */ 10 | @Service 11 | public class ItemReaderService2 implements ItemReader { 12 | private int count = 0; 13 | 14 | public String read() throws Exception { 15 | if (ItemProcessorService.message != null && count < ItemProcessorService.message.length) { 16 | return ItemProcessorService.message[count++]; 17 | } 18 | count = 0; 19 | return null; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/dylanz666/service/ItemWriterService.java: -------------------------------------------------------------------------------- 1 | package com.github.dylanz666.service; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.batch.item.ItemWriter; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author : dylanz 12 | * @since : 08/25/2020 13 | */ 14 | @Service 15 | public class ItemWriterService implements ItemWriter { 16 | private Logger logger = LoggerFactory.getLogger(this.getClass()); 17 | 18 | //在此处进行数据输出操作,如写入数据库、写入文件、打印log等,本例为打印log; 19 | public void write(List messages) throws Exception { 20 | for (String message : messages) { 21 | logger.info("Writing data: " + message); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/github/dylanz666/service/JobListener.java: -------------------------------------------------------------------------------- 1 | package com.github.dylanz666.service; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.batch.core.BatchStatus; 6 | import org.springframework.batch.core.JobExecution; 7 | import org.springframework.batch.core.JobExecutionListener; 8 | import org.springframework.stereotype.Service; 9 | 10 | /** 11 | * @author : dylanz 12 | * @since : 08/25/2020 13 | */ 14 | @Service 15 | public class JobListener implements JobExecutionListener { 16 | private Logger logger = LoggerFactory.getLogger(this.getClass()); 17 | 18 | public void beforeJob(JobExecution jobExecution) { 19 | logger.info("JOB IS STARTED."); 20 | } 21 | 22 | public void afterJob(JobExecution jobExecution) { 23 | if (jobExecution.getStatus() == BatchStatus.FAILED) { 24 | logger.info("JOB IS EXECUTED FAILED."); 25 | return; 26 | } 27 | if (jobExecution.getStatus() == BatchStatus.COMPLETED) { 28 | logger.info("JOB IS EXECUTED SUCCESSFULLY."); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | spring.batch.job.enabled=false 3 | spring.datasource.url=jdbc:h2:~/test 4 | spring.datasource.driverClassName=org.h2.Driver 5 | spring.datasource.username=sa 6 | spring.datasource.password=123456 7 | spring.h2.console.path=/h2-console 8 | spring.h2.console.enabled=true -------------------------------------------------------------------------------- /src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | logback 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | INFO 13 | 14 | true 15 | 16 | 22 | %red([%d{yyyy-MM-dd HH:mm:ss}]) %green([ %thread ]) %highlight([ %-5level ]) %boldMagenta([ %logger ]) - %cyan(%msg%n) 23 | 24 | GBK 25 | 26 | 27 | 32 | 33 | 34 | 35 | 36 | ${LOG_PATH}/current.log 37 | 38 | 39 | ${LOG_ARCHIVE}/app.%d.%i.log.gz 40 | 30 41 | 20GB 42 | 44 | 45 | 10MB 46 | 47 | 48 | 49 | [%d{yyyy-MM-dd HH:mm:ss}] [ %thread ] [ %-5level ] [ %logger ] - %msg%n 50 | GBK 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 62 | -------------------------------------------------------------------------------- /src/test/java/com/github/dylanz666/AppTest.java: -------------------------------------------------------------------------------- 1 | package com.github.dylanz666; 2 | 3 | import junit.framework.Test; 4 | import junit.framework.TestCase; 5 | import junit.framework.TestSuite; 6 | 7 | /** 8 | * Unit test for simple App. 9 | */ 10 | public class AppTest 11 | extends TestCase 12 | { 13 | /** 14 | * Create the test case 15 | * 16 | * @param testName name of the test case 17 | */ 18 | public AppTest( String testName ) 19 | { 20 | super( testName ); 21 | } 22 | 23 | /** 24 | * @return the suite of tests being tested 25 | */ 26 | public static Test suite() 27 | { 28 | return new TestSuite( AppTest.class ); 29 | } 30 | 31 | /** 32 | * Rigourous Test :-) 33 | */ 34 | public void testApp() 35 | { 36 | assertTrue( true ); 37 | } 38 | } 39 | --------------------------------------------------------------------------------