www.baeldung.com
Open in
urlscan Pro
172.66.43.8
Public Scan
URL:
https://www.baeldung.com/introduction-to-spring-batch
Submission Tags: falconsandbox
Submission: On November 20 via api from US — Scanned from US
Submission Tags: falconsandbox
Submission: On November 20 via api from US — Scanned from US
Form analysis
1 forms found in the DOMPOST https://www.getdrip.com/forms/15866254/submissions
<form method="post" action="https://www.getdrip.com/forms/15866254/submissions"><input type="hidden" value="https://www.getdrip.com/forms/15866254/submissions">
<div>
<div style="padding-top: 20px;">
<input class="input-email" name="fields[email]" id="drip-email" type="email" placeholder="Your Email" value="" label="Email Address">
</div>
<div><input name="website" id="website" type="text" placeholder="website" value="" label="Website" style="display:none"></div>
<div style="padding-top: 20px;"><button type="submit">FOLLOW THE SPRING</button></div>
</div>
</form>
Text Content
Baeldung Live - Do Not Process My Personal Information If you wish to opt-out of the sale, sharing to third parties, or processing of your personal or sensitive information for targeted advertising by us, please use the below opt-out section to confirm your selection. Please note that after your opt-out request is processed you may continue seeing interest-based ads based on personal information utilized by us or personal information disclosed to third parties prior to your opt-out. You may separately opt-out of the further disclosure of your personal information by third parties on the IAB’s list of downstream participants. This information may also be disclosed by us to third parties on the IAB’s List of Downstream Participants that may further disclose it to other third parties. * Personal Data Processing Opt Outs CONFIRM Data DeletionData AccessPrivacy Policy * * * Start Here * Courses ▼▲ * REST WITH SPRING BOOT The canonical reference for building a production grade API with Spring * LEARN SPRING SECURITY ▼▲ THE unique Spring Security education if you’re working with Java today * LEARN SPRING SECURITY CORE Focus on the Core of Spring Security 6 * LEARN SPRING SECURITY OAUTH Focus on the new OAuth2 stack in Spring Security 6 * LEARN SPRING From no experience to actually building stuff * LEARN SPRING DATA JPA The full guide to persistence with Spring Data JPA * Guides ▼▲ * SPRING BOOT Get started and go deep into Spring Boot 3 * PERSISTENCE The Persistence with Spring guides * REST The guides on building REST APIs with Spring * SECURITY The Spring Security guides * About ▼▲ * FULL ARCHIVE The high level overview of all the articles on the site. * BAELDUNG EBOOKS Discover all of our eBooks * ABOUT BAELDUNG About Baeldung. * * * INTRODUCTION TO SPRING BATCH Powered By 10 Sec Spring Security - Remember Me with Persistence (LSS - Module 3 - Lesson 3) Next Stay 1 Last updated: June 15, 2023 Written by: Eugen Paraschiv * Spring+ * reference * Spring Batch Course – launch – Black Friday 2024 – NPI (cat=Baeldung) Yes, we're now running the only sale of the year - our Black Friday launch. All Courses are 33% off until Monday, December 2nd: >> EXPLORE ACCESS NOW 1. OVERVIEW In this tutorial, we’re going to look at a practical, code-focused intro to Spring Batch. Spring Batch is a processing framework designed for robust execution of jobs. It’s current version 5.0.0 supports Spring 6 and Java 17. Here are a few interesting and practical use cases of the framework. 2. WORKFLOW BASICS Spring Batch follows the traditional batch architecture where a job repository does the work of scheduling and interacting with the job. A job can have more than one step. And every step typically follows the sequence of reading data, processing it and writing it. And of course the framework will do most of the heavy lifting for us here — especially when it comes to the low-level persistence work of dealing with the jobs — using h2 for the job repository. 2.1. EXAMPLE USE CASE The simple use case we’re going to tackle here is migrating some financial transaction data from CSV to XML. The input file has a very simple structure. It contains a transaction per line, made up of a username, the user id, the date of the transaction and the amount: username, userid, transaction_date, transaction_amount devendra, 1234, 31/10/2015, 10000 john, 2134, 3/12/2015, 12321 robin, 2134, 2/02/2015, 23411Copy 3. THE MAVEN POM Dependencies required for this project are Spring Core, Spring Batch and H2 database: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-oxm</artifactId> <version>6.1.4</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>2.1.214</version> </dependency> <dependency> <groupId>org.springframework.batch</groupId> <artifactId>spring-batch-core</artifactId> <version>5.1.1</version> </dependency>Copy 4. SPRING BATCH AND JOB CONFIG The basic Spring Batch configuration is displayed below along with our job description for the CSV to XML functionality. Java-based job configuration: @Profile("spring") public class SpringBatchConfig { @Value("input/record.csv") private Resource inputCsv; @Value("file:xml/output.xml") private Resource outputXml; @Bean public ItemReader<Transaction> itemReader() throws UnexpectedInputException, ParseException { FlatFileItemReader<Transaction> reader = new FlatFileItemReader<Transaction>(); DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer(); String[] tokens = { "username", "userid", "transactiondate", "amount" }; tokenizer.setNames(tokens); reader.setResource(inputCsv); DefaultLineMapper<Transaction> lineMapper = new DefaultLineMapper<Transaction>(); lineMapper.setLineTokenizer(tokenizer); lineMapper.setFieldSetMapper(new RecordFieldSetMapper()); reader.setLineMapper(lineMapper); return reader; } @Bean public ItemProcessor<Transaction, Transaction> itemProcessor() { return new CustomItemProcessor(); } @Bean public ItemWriter<Transaction> itemWriter(Marshaller marshaller) throws MalformedURLException { StaxEventItemWriter<Transaction> itemWriter = new StaxEventItemWriter<Transaction>(); itemWriter.setMarshaller(marshaller); itemWriter.setRootTagName("transactionRecord"); itemWriter.setResource(outputXml); return itemWriter; } @Bean public Marshaller marshaller() { Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); marshaller.setClassesToBeBound(new Class[] { Transaction.class }); return marshaller; } @Bean protected Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager, ItemReader<Transaction> reader, ItemProcessor<Transaction, Transaction> processor, ItemWriter<Transaction> writer, ) { return new StepBuilder("step1", jobRepository).<Transaction, Transaction> chunk(10, transactionManager) .reader(reader).processor(processor).writer(writer).build(); } @Bean(name = "firstBatchJob") public Job job(JobRepository jobRepository, @Qualifier("step1") Step step1) { return new JobBuilder("firstBatchJob", jobRepository).preventRestart().start(step1).build(); } public DataSource dataSource() { EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder(); return builder.setType(EmbeddedDatabaseType.H2) .addScript("classpath:org/springframework/batch/core/schema-drop-h2.sql") .addScript("classpath:org/springframework/batch/core/schema-h2.sql") .build(); } @Bean(name = "transactionManager") public PlatformTransactionManager getTransactionManager() { return new ResourcelessTransactionManager(); } @Bean(name = "jobRepository") public JobRepository getJobRepository() throws Exception { JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean(); factory.setDataSource(dataSource()); factory.setTransactionManager(getTransactionManager()); factory.afterPropertiesSet(); return factory.getObject(); } @Bean(name = "jobLauncher") public JobLauncher getJobLauncher() throws Exception { TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher(); jobLauncher.setJobRepository(getJobRepository()); jobLauncher.afterPropertiesSet(); return jobLauncher; } }Copy And the XML-based configuration: <bean id="itemReader" class="org.springframework.batch.item.file.FlatFileItemReader"> <property name="resource" value="input/record.csv" /> <property name="lineMapper"> <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper"> <property name="lineTokenizer"> <bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer"> <property name="names" value="username,userid,transactiondate,amount" /> </bean> </property> <property name="fieldSetMapper"> <bean class="com.baeldung.batch.service.RecordFieldSetMapper" /> </property> </bean> </property> <property name="linesToSkip" value="1" /> </bean> <bean id="itemProcessor" class="com.baeldung.batch.service.CustomItemProcessor" /> <bean id="itemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter"> <property name="resource" value="file:xml/output.xml" /> <property name="marshaller" ref="marshaller" /> <property name="rootTagName" value="transactionRecord" /> </bean> <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> <property name="classesToBeBound"> <list> <value>com.baeldung.batch.model.Transaction</value> </list> </property> </bean> <batch:job id="firstBatchJob"> <batch:step id="step1"> <batch:tasklet> <batch:chunk reader="itemReader" writer="itemWriter" processor="itemProcessor" commit-interval="10"> </batch:chunk> </batch:tasklet> </batch:step> </batch:job> <!-- connect to H2 database --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.h2.Driver" /> <property name="url" value="jdbc:h2:file:~/repository" /> <property name="username" value="" /> <property name="password" value="" /> </bean> <!-- create job-meta tables automatically --> <jdbc:initialize-database data-source="dataSource"> <jdbc:script location="org/springframework/batch/core/schema-drop-h2.sql" /> <jdbc:script location="org/springframework/batch/core/schema-h2.sql" /> </jdbc:initialize-database> <!-- stored job-meta in database --> <bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="transactionManager" ref="transactionManager" /> <property name="databaseType" value="h2" /> </bean> <bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" /> <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher"> <property name="jobRepository" ref="jobRepository" /> </bean>Copy Now that we have the whole config, let’s break it down and start discussing it. 4.1. READ DATA AND CREATE OBJECTS WITH ITEMREADER First, we configured the cvsFileItemReader that will read the data from the record.csv and convert it into the Transaction object: @SuppressWarnings("restriction") @XmlRootElement(name = "transactionRecord") public class Transaction { private String username; private int userId; private LocalDateTime transactionDate; private double amount; /* getters and setters for the attributes */ @Override public String toString() { return "Transaction [username=" + username + ", userId=" + userId + ", transactionDate=" + transactionDate + ", amount=" + amount + "]"; } }Copy To do so, it uses a custom mapper: public class RecordFieldSetMapper implements FieldSetMapper<Transaction> { public Transaction mapFieldSet(FieldSet fieldSet) throws BindException { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyy"); Transaction transaction = new Transaction(); transaction.setUsername(fieldSet.readString("username")); transaction.setUserId(fieldSet.readInt(1)); transaction.setAmount(fieldSet.readDouble(3)); String dateString = fieldSet.readString(2); transaction.setTransactionDate(LocalDate.parse(dateString, formatter).atStartOfDay()); return transaction; } }Copy 4.2. PROCESSING DATA WITH ITEMPROCESSOR We have created our own item processor, CustomItemProcessor. This doesn’t process anything related to the transaction object. All it does is pass the original object coming from reader to the writer: public class CustomItemProcessor implements ItemProcessor<Transaction, Transaction> { public Transaction process(Transaction item) { return item; } }Copy 4.3. WRITING OBJECTS TO THE FS WITH ITEMWRITER Finally, we are going to store this transaction into an XML file located at xml/output.xml: <bean id="itemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter"> <property name="resource" value="file:xml/output.xml" /> <property name="marshaller" ref="marshaller" /> <property name="rootTagName" value="transactionRecord" /> </bean>Copy 4.4. CONFIGURING THE BATCH JOB So, all we have to do is connect the dots with a job using the batch:job syntax. Note the commit-interval. That’s the number of transactions to be kept in memory before committing the batch to the itemWriter. It will hold the transactions in memory until that point (or until the end of the input data is encountered). The Java bean and correspondent XML configuration are displayed: @Bean protected Step step1(JobRepository jobRepository, PlatformTransactionManager transactionManager, @Qualifier("itemProcessor") ItemProcessor<Transaction, Transaction> processor, ItemWriter<Transaction> writer) { return new StepBuilder("step1", jobRepository) .<Transaction, Transaction> chunk(10, transactionManager) .reader(itemReader(inputCsv)) .processor(processor) .writer(writer) .build(); }Copy <batch:job id="firstBatchJob"> <batch:step id="step1"> <batch:tasklet> <batch:chunk reader="itemReader" writer="itemWriter" processor="itemProcessor" commit-interval="10"> </batch:chunk> </batch:tasklet> </batch:step> </batch:job>Copy 4.5. RUNNING THE BATCH JOB Now let’s set up and run everything: @Profile("spring") public class App { public static void main(String[] args) { // Spring Java config AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); context.register(SpringConfig.class); context.register(SpringBatchConfig.class); context.refresh(); JobLauncher jobLauncher = (JobLauncher) context.getBean("jobLauncher"); Job job = (Job) context.getBean("firstBatchJob"); System.out.println("Starting the batch job"); try { JobExecution execution = jobLauncher.run(job, new JobParameters()); System.out.println("Job Status : " + execution.getStatus()); System.out.println("Job completed"); } catch (Exception e) { e.printStackTrace(); System.out.println("Job failed"); } } }Copy We run our Spring application using -Dspring.profiles.active=spring profile. In the next section, we configure our example in a Spring Boot application. 5. SPRING BOOT CONFIGURATION In this section, we’ll create a Spring Boot application and convert the previous Spring Batch Config to run in the Spring Boot environment. In fact, this is roughly the equivalent of the previous Spring Batch example. 5.1. MAVEN DEPENDENCIES Let’s start by declaring spring-boot-starter-batch dependency in a Spring Boot application in the pom.xml: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-batch</artifactId> </dependency>Copy We need a database to store the Spring Batch job information. In this tutorial, we use an in-memory H2 database. Therefore, we need to use h2 with Spring Boot: <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>2.1.214</version> <scope>runtime</scope> </dependency>Copy 5.2. SPRING BOOT CONFIG We use the @Profile annotation to distinguish between the Spring and Spring Boot configurations. We set the spring-boot profile in our application: @SpringBootApplication public class SpringBatchApplication { public static void main(String[] args) { SpringApplication springApp = new SpringApplication(SpringBatchApplication.class); springApp.setAdditionalProfiles("spring-boot"); springApp.run(args); } }Copy 5.3. SPRING BATCH JOB CONFIG We use the batch job configuration the same as the SpringBatchConfig class from earlier: @Configuration public class SpringBootBatchConfig { @Value("input/record.csv") private Resource inputCsv; @Value("input/recordWithInvalidData.csv") private Resource invalidInputCsv; @Value("file:xml/output.xml") private Resource outputXml; // ... }Copy Starting with spring-boot 3.0, @EnableBatchProcessing annotation is discouraged. We declare manually JobRepository, JobLauncher and TransactionManager beans. In addition, JobBuilderFactory and StepBuilderFactory are deprecated, and it’s recommended to use JobBuilder and StepBuilder class with the name of the job/step builder. 6. CONCLUSION In this article, we learned how to work with Spring Batch and how to use it in a simple use case. We saw how we can easily develop our batch processing pipeline and how we can customize different stages in reading, processing, and writing. As always, the full implementation of this article can be found in over on GitHub. Course – launch – Black Friday 2024 – NPI (All) Yes, we're now running the only sale of the year - our Black Friday launch. All Courses are 33% off until Monday, December, 2nd: >> EXPLORE ACCESS NOW COURSES * All Courses * Baeldung All Access * Baeldung All Team Access * The Courses Platform SERIES * Java “Back to Basics” Tutorial * Jackson JSON Series * Apache HttpClient Series * REST with Spring Series * Spring Persistence Series * Security with Spring * Spring Reactive Series ABOUT * About Baeldung * The Full Archive * Editors * Our Partners * Partner with Baeldung * eBooks * FAQ * Baeldung Pro * Terms of Service * Privacy Policy * Company Info * Contact Follow the Spring Category Follow the Spring category to get regular info about the new articles and tutorials we publish here. FOLLOW THE SPRING Freestar.com