การประมวลผลแบบเป็นกลุ่ม - ถูกกำหนดโดยการประมวลผลในพื้นหลังที่เน้นจำนวนมากไม่โต้ตอบและมักจะทำงานเป็นเวลานานซึ่งใช้กันอย่างแพร่หลายในแทบทุกอุตสาหกรรมและถูกนำไปใช้กับงานที่หลากหลาย การประมวลผลแบบกลุ่มอาจเป็นข้อมูลหรือใช้การคำนวณอย่างเข้มข้นดำเนินการตามลำดับหรือควบคู่กันและอาจเริ่มต้นผ่านรูปแบบการเรียกใช้งานต่างๆรวมถึงเฉพาะกิจการกำหนดเวลาและตามความต้องการ
บทช่วยสอน Spring Batch นี้อธิบายถึงรูปแบบการเขียนโปรแกรมและภาษาโดเมนของแอปพลิเคชันชุดงานโดยทั่วไปและโดยเฉพาะอย่างยิ่งจะแสดงแนวทางที่เป็นประโยชน์บางประการในการออกแบบและพัฒนาแอปพลิเคชันชุดงานโดยใช้ปัจจุบัน ชุดสปริง 3.0.7 รุ่น.
Spring Batch คืออะไร?
Spring Batch เป็นเฟรมเวิร์กที่มีน้ำหนักเบาและครอบคลุมซึ่งออกแบบมาเพื่ออำนวยความสะดวกในการพัฒนาแอปพลิเคชันชุดงานที่มีประสิทธิภาพ นอกจากนี้ยังมีบริการทางเทคนิคขั้นสูงและคุณสมบัติที่รองรับงานแบตช์ปริมาณมากและประสิทธิภาพสูงผ่านเทคนิคการเพิ่มประสิทธิภาพและการแบ่งพาร์ติชัน Spring Batch สร้างขึ้นจาก POJO ตาม แนวทางการพัฒนาของ กรอบสปริง คุ้นเคยกับทุกคน นักพัฒนา Spring ที่มีประสบการณ์ .
โดยตัวอย่างเช่นบทความนี้พิจารณาซอร์สโค้ดจากโครงการตัวอย่างที่โหลดไฟล์ลูกค้าที่จัดรูปแบบ XML กรองลูกค้าตามแอตทริบิวต์ต่างๆและส่งออกรายการที่กรองไปยังไฟล์ข้อความ ซอร์สโค้ดสำหรับตัวอย่าง Spring Batch ของเรา (ซึ่งใช้ประโยชน์จากไฟล์ ลอมบอก คำอธิบายประกอบ) สามารถใช้ได้ ที่นี่ บน GitHub และต้องใช้ Java SE 8 และ Maven
เป็นสิ่งสำคัญสำหรับนักพัฒนาแบทช์ที่จะต้องคุ้นเคยและสบายใจกับแนวคิดหลักของการประมวลผลแบบกลุ่ม แผนภาพด้านล่างเป็นเวอร์ชันที่เรียบง่ายของสถาปัตยกรรมการอ้างอิงแบทช์ที่ได้รับการพิสูจน์แล้วผ่านการใช้งานหลายทศวรรษบนแพลตฟอร์มต่างๆ แนะนำแนวคิดหลักและคำศัพท์ที่เกี่ยวข้องกับการประมวลผลชุดงานตามที่ Spring Batch ใช้
ดังที่แสดงในตัวอย่างการประมวลผลแบทช์ของเราโดยทั่วไปกระบวนการแบตช์จะถูกห่อหุ้มโดย Job
ประกอบด้วยหลาย Step
s แต่ละ Step
โดยทั่วไปจะมี ItemReader
, ItemProcessor
และ ItemWriter
ก Job
ดำเนินการโดย JobLauncher
และข้อมูลเมตาเกี่ยวกับงานที่กำหนดค่าและดำเนินการจะถูกเก็บไว้ใน JobRepository
แต่ละ Job
อาจเชื่อมโยงกับหลาย JobInstance
s ซึ่งแต่ละคำนิยามโดยเฉพาะโดยเฉพาะ JobParameters
ที่ใช้ในการเริ่มงานชุดงาน การรันแต่ละครั้งของ JobInstance
จะเรียกว่า JobExecution
แต่ละ JobExecution
โดยทั่วไปจะติดตามสิ่งที่เกิดขึ้นระหว่างการวิ่งเช่นสถานะปัจจุบันและการออกเวลาเริ่มต้นและเวลาสิ้นสุดเป็นต้น
ก Step
เป็นเฟสที่เป็นอิสระและเฉพาะเจาะจงของชุดงาน Job
ดังนั้นทุกๆ Job
ประกอบด้วยหนึ่งหรือมากกว่า Step
s คล้ายกับ a Job
, a Step
มีบุคคล StepExecution
ซึ่งแสดงถึงความพยายามเพียงครั้งเดียวในการดำเนินการ Step
StepExecution
จัดเก็บข้อมูลเกี่ยวกับสถานะปัจจุบันและการออกเวลาเริ่มต้นและเวลาสิ้นสุดและอื่น ๆ ตลอดจนการอ้างอิงถึง Step
ที่เกี่ยวข้อง และ JobExecution
ตัวอย่าง.
อัน ExecutionContext
คือชุดของคู่คีย์ - ค่าที่มีข้อมูลที่กำหนดขอบเขตเป็น StepExecution
หรือ JobExecution
. Spring Batch ยังคงมี ExecutionContext
ซึ่งจะช่วยในกรณีที่คุณต้องการรีสตาร์ทการรันแบตช์ (เช่นเมื่อเกิดข้อผิดพลาดร้ายแรงเป็นต้น) สิ่งที่จำเป็นคือการใส่วัตถุใด ๆ ที่จะใช้ร่วมกันระหว่างขั้นตอนต่างๆในบริบทและกรอบงานจะดูแลส่วนที่เหลือ หลังจากรีสตาร์ทค่าจากก่อนหน้า ExecutionContext
จะถูกเรียกคืนจากฐานข้อมูลและนำไปใช้
JobRepository
เป็นกลไกใน Spring Batch ที่ทำให้การคงอยู่ทั้งหมดนี้เป็นไปได้ ให้การดำเนินการ CRUD สำหรับ JobLauncher
, Job
และ Step
อินสแตนซ์ ครั้งหนึ่ง Job
เปิดตัว a JobExecution
ได้มาจากที่เก็บและในระหว่างการดำเนินการ StepExecution
และ JobExecution
อินสแตนซ์จะยังคงอยู่ในที่เก็บ
ข้อดีอย่างหนึ่งของ Spring Batch คือการอ้างอิงโปรเจ็กต์นั้นมีน้อยมากซึ่งทำให้ง่ายต่อการเริ่มต้นและทำงานอย่างรวดเร็ว การอ้างอิงบางส่วนที่มีอยู่นั้นระบุไว้อย่างชัดเจนและอธิบายไว้ใน pom.xml
ของโปรเจ็กต์ซึ่งสามารถเข้าถึงได้ ที่นี่ .
การเริ่มต้นแอปพลิเคชันที่แท้จริงเกิดขึ้นในชั้นเรียนซึ่งมีลักษณะดังนี้:
@EnableBatchProcessing @SpringBootApplication public class BatchApplication { public static void main(String[] args) { prepareTestData(1000); SpringApplication.run(BatchApplication.class, args); } }
@EnableBatchProcessing
คำอธิบายประกอบเปิดใช้งานคุณสมบัติ Spring Batch และจัดเตรียมการกำหนดค่าพื้นฐานสำหรับการตั้งค่างานชุดงาน
@SpringBootApplication
คำอธิบายประกอบมาจากไฟล์ สปริงบูต โครงการที่จัดเตรียมแอปพลิเคชันแบบสปริงพร้อมใช้งานแบบสแตนด์อโลน ระบุคลาสการกำหนดค่าที่ประกาศ Spring beans อย่างน้อยหนึ่งคลาสและยังเรียกใช้การกำหนดค่าอัตโนมัติและการสแกนส่วนประกอบของ Spring
โครงการตัวอย่างของเรามีเพียงงานเดียวที่กำหนดค่าโดย CustomerReportJobConfig
ด้วยการฉีด JobBuilderFactory
และ StepBuilderFactory
. สามารถกำหนดโครงร่างงานขั้นต่ำได้ใน CustomerReportJobConfig
ดังต่อไปนี้:
@Configuration public class CustomerReportJobConfig { @Autowired private JobBuilderFactory jobBuilders; @Autowired private StepBuilderFactory stepBuilders; @Bean public Job customerReportJob() { return jobBuilders.get('customerReportJob') .start(taskletStep()) .next(chunkStep()) .build(); } @Bean public Step taskletStep() { return stepBuilders.get('taskletStep') .tasklet(tasklet()) .build(); } @Bean public Tasklet tasklet() { return (contribution, chunkContext) -> { return RepeatStatus.FINISHED; }; } }
มีสองวิธีหลักในการสร้างขั้นตอน
แนวทางหนึ่งดังที่แสดงในตัวอย่างข้างต้นคือ ตามภารกิจ . ก Tasklet
รองรับอินเทอร์เฟซแบบธรรมดาที่มีเพียงวิธีเดียวคือ execute()
ซึ่งเรียกซ้ำ ๆ จนกว่าจะส่งคืน RepeatStatus.FINISHED
หรือแสดงข้อยกเว้นเพื่อส่งสัญญาณความล้มเหลว แต่ละการโทรไปที่ Tasklet
ถูกห่อด้วยธุรกรรม
อีกแนวทางหนึ่ง การประมวลผลแบบก้อน หมายถึงการอ่านข้อมูลตามลำดับและการสร้าง 'ชิ้นส่วน' ที่จะเขียนออกมาภายในขอบเขตธุรกรรม แต่ละรายการจะอ่านจาก ItemReader
ส่งไปยัง ItemProcessor
และรวม เมื่อจำนวนรายการที่อ่านเท่ากับช่วงเวลาการคอมมิตชิ้นส่วนทั้งหมดจะถูกเขียนออกมาผ่านทาง ItemWriter
จากนั้นธุรกรรมจะถูกคอมมิต ขั้นตอนที่เน้นเป็นก้อนสามารถกำหนดค่าได้ดังนี้:
@Bean public Job customerReportJob() { return jobBuilders.get('customerReportJob') .start(taskletStep()) .next(chunkStep()) .build(); } @Bean public Step chunkStep() { return stepBuilders.get('chunkStep') .chunk(20) .reader(reader()) .processor(processor()) .writer(writer()) .build(); }
chunk()
เมธอดสร้างขั้นตอนที่ประมวลผลไอเท็มเป็นชิ้น ๆ ตามขนาดที่กำหนดโดยแต่ละชิ้นจะถูกส่งผ่านไปยังตัวอ่านตัวประมวลผลและตัวเขียนที่ระบุ วิธีการเหล่านี้จะกล่าวถึงโดยละเอียดในส่วนถัดไปของบทความนี้
สำหรับแอปพลิเคชัน Spring Batch ของเราในการอ่านรายชื่อลูกค้าจากไฟล์ XML เราจำเป็นต้องจัดเตรียมอินเทอร์เฟซ org.springframework.batch.item.ItemReader
:
public interface ItemReader { T read() throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException; }
อัน ItemReader
ให้ข้อมูลและคาดว่าจะอยู่ในสถานะ โดยทั่วไปจะเรียกหลายครั้งสำหรับแต่ละชุดโดยแต่ละครั้งจะเรียกไปที่ read()
ส่งคืนค่าถัดไปและส่งคืนในที่สุด null
เมื่อข้อมูลอินพุตทั้งหมดหมดลง
Spring Batch มีการใช้งาน ItemReader
แบบสำเร็จรูปซึ่งสามารถใช้เพื่อวัตถุประสงค์ที่หลากหลายเช่นการอ่านคอลเลคชันไฟล์การรวม JMS และ JDBC ตลอดจนแหล่งที่มาหลายแหล่งเป็นต้น
ในแอปพลิเคชันตัวอย่างของเรา CustomerItemReader
คลาสมอบสิทธิ์จริง read()
เรียกไปยังอินสแตนซ์เริ่มต้นอย่างเกียจคร้านของ IteratorItemReader
ชั้น:
public class CustomerItemReader implements ItemReader { private final String filename; private ItemReader delegate; public CustomerItemReader(final String filename) { this.filename = filename; } @Override public Customer read() throws Exception { if (delegate == null) { delegate = new IteratorItemReader(customers()); } return delegate.read(); } private List customers() throws FileNotFoundException { try (XMLDecoder decoder = new XMLDecoder(new FileInputStream(filename))) { return (List) decoder.readObject(); } } }
Spring bean สำหรับการใช้งานนี้ถูกสร้างขึ้นด้วย @Component
และ @StepScope
คำอธิบายประกอบเพื่อให้ Spring ทราบว่าคลาสนี้เป็นองค์ประกอบ Spring ที่กำหนดขอบเขตขั้นตอนและจะถูกสร้างขึ้นหนึ่งครั้งต่อการดำเนินการขั้นตอนดังนี้:
@StepScope @Bean public ItemReader reader() { return new CustomerItemReader(XML_FILE); }
ItemProcessors
แปลงรายการอินพุตและแนะนำตรรกะทางธุรกิจในสถานการณ์การประมวลผลที่มุ่งเน้นสินค้า ต้องมีการใช้งานอินเทอร์เฟซ org.springframework.batch.item.ItemProcessor
:
public interface ItemProcessor { O process(I item) throws Exception; }
วิธีการ process()
ยอมรับหนึ่งอินสแตนซ์ของ I
คลาสและอาจส่งคืนอินสแตนซ์ประเภทเดียวกันหรือไม่ก็ได้ กลับ null
บ่งชี้ว่าไม่ควรประมวลผลรายการต่อไป ตามปกติ Spring มีโปรเซสเซอร์มาตรฐานไม่กี่ตัวเช่น CompositeItemProcessor
ที่ส่งผ่านรายการผ่านลำดับของการฉีด ItemProcessor
s และ a ValidatingItemProcessor
ที่ตรวจสอบอินพุต
ในกรณีของแอปพลิเคชันตัวอย่างของเราโปรเซสเซอร์จะใช้เพื่อกรองลูกค้าตามข้อกำหนดต่อไปนี้:
ข้อกำหนด 'เดือนปัจจุบัน' จะดำเนินการผ่านทาง ItemProcessor
ที่กำหนดเอง:
public class BirthdayFilterProcessor implements ItemProcessor { @Override public Customer process(final Customer item) throws Exception { if (new GregorianCalendar().get(Calendar.MONTH) == item.getBirthday().get(Calendar.MONTH)) { return item; } return null; } }
ข้อกำหนด 'จำนวนธุรกรรมที่ จำกัด ' ถูกนำมาใช้เป็น ValidatingItemProcessor
:
public class TransactionValidatingProcessor extends ValidatingItemProcessor { public TransactionValidatingProcessor(final int limit) { super( item -> { if (item.getTransactions() >= limit) { throw new ValidationException('Customer has less than ' + limit + ' transactions'); } } ); setFilter(true); } }
จากนั้นโปรเซสเซอร์คู่นี้จะถูกห่อหุ้มไว้ภายใน CompositeItemProcessor
ที่ใช้รูปแบบผู้รับมอบสิทธิ์:
@StepScope @Bean public ItemProcessor processor() { final CompositeItemProcessor processor = new CompositeItemProcessor(); processor.setDelegates(Arrays.asList(new BirthdayFilterProcessor(), new TransactionValidatingProcessor(5))); return processor; }
สำหรับการส่งออกข้อมูล Spring Batch จะมีอินเทอร์เฟซ org.springframework.batch.item.ItemWriter
สำหรับการทำให้เป็นอนุกรมวัตถุตามความจำเป็น:
public interface ItemWriter { void write(List items) throws Exception; }
write()
วิธีการรับผิดชอบในการตรวจสอบให้แน่ใจว่ามีการล้างบัฟเฟอร์ภายในใด ๆ หากมีการใช้งานธุรกรรมมักจะต้องทิ้งผลลัพธ์ในการย้อนกลับในภายหลัง ทรัพยากรที่ผู้เขียนกำลังส่งข้อมูลโดยปกติควรสามารถจัดการได้เอง มีการใช้งานมาตรฐานเช่น CompositeItemWriter
, JdbcBatchItemWriter
, JmsItemWriter
, JpaItemWriter
, SimpleMailMessageItemWriter
และอื่น ๆ
ในแอปพลิเคชันตัวอย่างของเรารายชื่อลูกค้าที่ถูกกรองจะเขียนไว้ดังนี้:
public class CustomerItemWriter implements ItemWriter, Closeable { private final PrintWriter writer; public CustomerItemWriter() { OutputStream out; try { out = new FileOutputStream('output.txt'); } catch (FileNotFoundException e) { out = System.out; } this.writer = new PrintWriter(out); } @Override public void write(final List items) throws Exception { for (Customer item : items) { writer.println(item.toString()); } } @PreDestroy @Override public void close() throws IOException { writer.close(); } }
ตามค่าเริ่มต้น Spring Batch จะเรียกใช้งานทั้งหมดที่สามารถค้นหาได้ (เช่นที่กำหนดค่าเป็น CustomerReportJobConfig
) เมื่อเริ่มต้น หากต้องการเปลี่ยนลักษณะการทำงานนี้ให้ปิดใช้งานการเรียกใช้งานเมื่อเริ่มต้นโดยเพิ่มคุณสมบัติต่อไปนี้ใน application.properties
:
ความเสี่ยงจากอัตราแลกเปลี่ยนเป็นความเสี่ยงหลักที่:
spring.batch.job.enabled=false
จากนั้นการตั้งเวลาจริงจะทำได้โดยการเพิ่ม @EnableScheduling
คำอธิบายประกอบไปยังคลาสคอนฟิกูเรชันและ @Scheduled
คำอธิบายประกอบไปยังเมธอดที่เรียกใช้งานตัวเอง การจัดกำหนดการสามารถกำหนดค่าด้วยความล่าช้าอัตราหรือนิพจน์ cron:
// run every 5000 msec (i.e., every 5 secs) @Scheduled(fixedRate = 5000) public void run() throws Exception { JobExecution execution = jobLauncher.run( customerReportJob(), new JobParametersBuilder().toJobParameters() ); }
มีปัญหากับตัวอย่างข้างต้นแม้ว่า ในเวลาดำเนินการงานจะประสบความสำเร็จในครั้งแรกเท่านั้น เมื่อเปิดตัวครั้งที่สอง (เช่นหลังจากห้าวินาที) ข้อความต่อไปนี้จะสร้างข้อความต่อไปนี้ในบันทึก (โปรดทราบว่าใน Spring Batch a JobInstanceAlreadyCompleteException
เวอร์ชันก่อนหน้าจะถูกโยนทิ้ง):
INFO 36988 --- [pool-2-thread-1] o.s.b.c.l.support.SimpleJobLauncher : Job: [SimpleJob: [name=customerReportJob]] launched with the following parameters: [{}] INFO 36988 --- [pool-2-thread-1] o.s.batch.core.job.SimpleStepHandler : Step already complete or not restartable, so no action to execute: StepExecution: id=1, version=3, name=taskletStep, status=COMPLETED, exitStatus=COMPLETED, readCount=0, filterCount=0, writeCount=0 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=1, rollbackCount=0, exitDescription= INFO 36988 --- [pool-2-thread-1] o.s.batch.core.job.SimpleStepHandler : Step already complete or not restartable, so no action to execute: StepExecution: id=2, version=53, name=chunkStep, status=COMPLETED, exitStatus=COMPLETED, readCount=1000, filterCount=982, writeCount=18 readSkipCount=0, writeSkipCount=0, processSkipCount=0, commitCount=51, rollbackCount=0, exitDescription=
สิ่งนี้เกิดขึ้นเนื่องจากเฉพาะ JobInstance
s เท่านั้นที่สามารถสร้างและดำเนินการได้และ Spring Batch จะไม่มีทางแยกความแตกต่างระหว่างครั้งแรกและครั้งที่สอง JobInstance
มีสองวิธีในการหลีกเลี่ยงปัญหานี้เมื่อคุณจัดกำหนดการงานชุดงาน
อย่างหนึ่งคือต้องแน่ใจว่าได้แนะนำพารามิเตอร์ที่ไม่ซ้ำกันอย่างน้อยหนึ่งพารามิเตอร์ (เช่นเวลาเริ่มต้นจริงในหน่วยนาโนวินาที) ให้กับแต่ละงาน:
@Scheduled(fixedRate = 5000) public void run() throws Exception { jobLauncher.run( customerReportJob(), new JobParametersBuilder().addLong('uniqueness', System.nanoTime()).toJobParameters() ); }
หรือคุณสามารถเปิดงานถัดไปตามลำดับ JobInstance
s ที่กำหนดโดย JobParametersIncrementer
แนบกับงานที่ระบุด้วย SimpleJobOperator.startNextInstance()
:
@Autowired private JobOperator operator; @Autowired private JobExplorer jobs; @Scheduled(fixedRate = 5000) public void run() throws Exception { List lastInstances = jobs.getJobInstances(JOB_NAME, 0, 1); if (lastInstances.isEmpty()) { jobLauncher.run(customerReportJob(), new JobParameters()); } else { operator.startNextInstance(JOB_NAME); } }
โดยปกติแล้วในการรันการทดสอบหน่วยในแอปพลิเคชัน Spring Boot เฟรมเวิร์กจะต้องโหลด ApplicationContext
ที่เกี่ยวข้อง มีการใช้คำอธิบายประกอบสองรายการเพื่อจุดประสงค์นี้:
@RunWith(SpringRunner.class) @ContextConfiguration(classes = {...})
มีคลาสยูทิลิตี้ org.springframework.batch.test.JobLauncherTestUtils
เพื่อทดสอบงานแบทช์ มีวิธีการเปิดตัวงานทั้งหมดรวมทั้งอนุญาตให้ทำการทดสอบแบบ end-to-end ของแต่ละขั้นตอนโดยไม่ต้องดำเนินการทุกขั้นตอนในงาน ต้องประกาศว่าเป็นถั่วสปริง:
@Configuration public class BatchTestConfiguration { @Bean public JobLauncherTestUtils jobLauncherTestUtils() { return new JobLauncherTestUtils(); } }
การทดสอบทั่วไปสำหรับงานและขั้นตอนมีลักษณะดังนี้ (และสามารถใช้กรอบการเยาะเย้ยได้เช่นกัน):
@RunWith(SpringRunner.class) @ContextConfiguration(classes = {BatchApplication.class, BatchTestConfiguration.class}) public class CustomerReportJobConfigTest { @Autowired private JobLauncherTestUtils testUtils; @Autowired private CustomerReportJobConfig config; @Test public void testEntireJob() throws Exception { final JobExecution result = testUtils.getJobLauncher().run(config.customerReportJob(), testUtils.getUniqueJobParameters()); Assert.assertNotNull(result); Assert.assertEquals(BatchStatus.COMPLETED, result.getStatus()); } @Test public void testSpecificStep() { Assert.assertEquals(BatchStatus.COMPLETED, testUtils.launchStep('taskletStep').getStatus()); } }
Spring Batch แนะนำขอบเขตเพิ่มเติมสำหรับขั้นตอนและบริบทงาน ออบเจ็กต์ในขอบเขตเหล่านี้ใช้คอนเทนเนอร์ Spring เป็นโรงงานอ็อบเจ็กต์ดังนั้นจึงมีเพียงอินสแตนซ์ของแต่ละ bean ต่อขั้นตอนการดำเนินการหรืองาน นอกจากนี้ยังมีการสนับสนุนสำหรับการเชื่อมโยงข้อมูลอ้างอิงในช่วงปลายซึ่งสามารถเข้าถึงได้จาก StepContext
หรือ JobContext
. คอมโพเนนต์ที่กำหนดค่าในรันไทม์เป็นขั้นตอนหรือขอบเขตงานนั้นยากที่จะทดสอบเป็นส่วนประกอบแบบสแตนด์อโลนเว้นแต่คุณจะมีวิธีตั้งค่าบริบทราวกับว่าอยู่ในขั้นตอนหรือการดำเนินการงาน นั่นคือเป้าหมายของ org.springframework.batch.test.StepScopeTestExecutionListener
และ org.springframework.batch.test.StepScopeTestUtils
ส่วนประกอบใน Spring Batch รวมถึง JobScopeTestExecutionListener
และ JobScopeTestUtils
.
TestExecutionListeners
ได้รับการประกาศในระดับคลาสและหน้าที่ของมันคือการสร้างบริบทการดำเนินการขั้นตอนสำหรับแต่ละวิธีการทดสอบ ตัวอย่างเช่น:
@RunWith(SpringRunner.class) @TestExecutionListeners({DependencyInjectionTestExecutionListener.class, StepScopeTestExecutionListener.class}) @ContextConfiguration(classes = {BatchApplication.class, BatchTestConfiguration.class}) public class BirthdayFilterProcessorTest { @Autowired private BirthdayFilterProcessor processor; public StepExecution getStepExecution() { return MetaDataInstanceFactory.createStepExecution(); } @Test public void filter() throws Exception { final Customer customer = new Customer(); customer.setId(1); customer.setName('name'); customer.setBirthday(new GregorianCalendar()); Assert.assertNotNull(processor.process(customer)); } }
มีสอง TestExecutionListener
s หนึ่งมาจากกรอบการทดสอบ Spring Test ปกติและจัดการกับการฉีดพึ่งพาจากบริบทแอปพลิเคชันที่กำหนดค่าไว้ อีกอันคือ Spring Batch StepScopeTestExecutionListener
ที่ตั้งค่าบริบทขอบเขตขั้นตอนสำหรับการฉีดการพึ่งพาในการทดสอบหน่วย ก StepContext
ถูกสร้างขึ้นสำหรับระยะเวลาของวิธีการทดสอบและพร้อมใช้งานสำหรับการอ้างอิงใด ๆ ที่ถูกฉีดเข้าไป พฤติกรรมเริ่มต้นคือการสร้าง StepExecution
ด้วยคุณสมบัติคงที่ หรืออีกวิธีหนึ่งคือ StepContext
ได้โดยกรณีทดสอบเป็นวิธีการจากโรงงานที่ส่งคืนประเภทที่ถูกต้อง
อีกแนวทางหนึ่งขึ้นอยู่กับ StepScopeTestUtils
ชั้นยูทิลิตี้ คลาสนี้ใช้เพื่อสร้างและจัดการ StepScope
ในการทดสอบหน่วยด้วยวิธีที่ยืดหยุ่นมากขึ้นโดยไม่ต้องใช้การฉีดแบบพึ่งพา ตัวอย่างเช่นการอ่าน ID ของลูกค้าที่กรองโดยโปรเซสเซอร์ข้างต้นสามารถทำได้ดังนี้:
@Test public void filterId() throws Exception { final Customer customer = new Customer(); customer.setId(1); customer.setName('name'); customer.setBirthday(new GregorianCalendar()); final int id = StepScopeTestUtils.doInStepScope( getStepExecution(), () -> processor.process(customer).getId() ); Assert.assertEquals(1, id); }
บทความนี้แนะนำพื้นฐานบางประการของการออกแบบและพัฒนาแอปพลิเคชัน Spring Batch อย่างไรก็ตามยังมีหัวข้อและความสามารถขั้นสูงอีกมากมายเช่นการปรับขนาดการประมวลผลแบบขนานผู้ฟังและอื่น ๆ อีกมากมายที่ไม่ได้กล่าวถึงในบทความนี้ หวังว่าบทความนี้จะเป็นพื้นฐานที่มีประโยชน์สำหรับการเริ่มต้น
คุณสามารถดูข้อมูลเกี่ยวกับหัวข้อขั้นสูงเหล่านี้ได้ในไฟล์ เอกสาร Spring Back อย่างเป็นทางการ สำหรับ Spring Batch
Spring Batch เป็นเฟรมเวิร์กที่มีน้ำหนักเบาและครอบคลุมซึ่งออกแบบมาเพื่ออำนวยความสะดวกในการพัฒนาแอปพลิเคชันชุดงานที่มีประสิทธิภาพ นอกจากนี้ยังมีบริการทางเทคนิคขั้นสูงและคุณสมบัติที่รองรับงานแบตช์ปริมาณมากและประสิทธิภาพสูงผ่านเทคนิคการเพิ่มประสิทธิภาพและการแบ่งพาร์ติชัน
'ขั้นตอน' เป็นขั้นตอนเฉพาะของชุดงาน 'งาน' ซึ่งทุกงานประกอบด้วยขั้นตอนอย่างน้อยหนึ่งขั้นตอน
'JobRepository' เป็นกลไกใน Spring Batch ที่ทำให้การคงอยู่ทั้งหมดนี้เป็นไปได้ ให้การดำเนินการ CRUD สำหรับการสร้างอินสแตนซ์ JobLauncher, Job และ Step
แนวทางหนึ่งคือใช้งานแบบใช้งานโดย Tasklet สนับสนุนอินเทอร์เฟซที่เรียบง่ายด้วยวิธีการดำเนินการเดียว () อีกวิธีหนึ่งคือ ** การประมวลผลเชิงกลุ่ม ** หมายถึงการอ่านข้อมูลตามลำดับและสร้าง 'กลุ่ม' ที่จะเขียนออกมาภายในขอบเขตธุรกรรม