spring-batch-tutorials/hello-world-java at master · langmi/spring-batch-tutorials · GitHub
Skip to content

Latest commit

 

History

History

README.md

"Hello World!" with Spring Batch 2.1

Logo

Summary

In this tutorial, we will create a really simple Hello World! program with Spring Batch Version 2.1 and learn some basics for this amazing Java batch processing framework.

You will need at least a basic understanding of the Spring (Core) framework to get along with the tutorial.

For the Impatient

If you are in a hurry or just the code-first type, you can jump right to the source here on my github repository, dive into the hello-world-java directory.

Introduction

What is Spring Batch?

From the official Spring Batch website:

Spring Batch is a lightweight, comprehensive batch framework designed to enable the development of robust batch applications vital for the daily operations of enterprise systems.

Doesn't that sound like the usual sales pitch? Ok lets try it with (my) own words:

Spring Batch is a framework, which does the grunt work for your Java batch needs and provides lots of ready-to-use implementations to keep your own code minimal.

Basic Spring Batch Concepts

The official reference covers the Spring Batch concepts in every detail, but for this tutorial we can start with a more simplified view:

A Spring Batch program usually consists of a Job, which encapsulates a flow of steps, where a step can be seen as abstract isolated unit of work. Here that is visualized with a sequential flow example:

Spring Batch Job

A standard Step reads data, processes it and writes data, until the data from the reader is exhausted.

Spring Batch Step

The data is handled with a so called Chunk Oriented Processing approach, where the data is read individually, processed individually, but written in chunks.

Spring Batch Chunk

The chunks play a role for the transactional behavior too, Spring Batch commits a transaction after each chunk. Thats enough for the basic concepts, time to get ready for some coding.

Get Ready For Coding!

The Spring Batch framework is really lightweight, but that comes at the prize of a little more complex XML configuration. It is a Spring framework after all.

Spring Batch Configuration

The configuration needed to get a Spring Batch program running roughly consists of two parts:

  • Spring Batch infrastructure
  • Spring Batch Job definition

Spring Batch Infrastructure

Under the hood Spring Batch works with some tables to keep the state of the jobs and steps and to provide re-startability. The tables are accessed with a DAO called Job Repository and to start a Job the framework provides a Job Launcher. Because a job works with transactions, a transaction manager is mandatory.

To keep this tutorial simple we use a table-less Job Repository and a dummy transaction manager, translated to the Spring and Spring Batch XML configuration it looks like this:

<bean id="jobLauncher" 
      class="org.springframework.batch.core.launch.support.SimpleJobLauncher"
      p:jobRepository-ref="jobRepository" />

<bean id="jobRepository" 
      class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"
      p:transactionManager-ref="transactionManager" />

<bean id="transactionManager" 
      class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />

This is at the same time the most minimal Spring Batch infrastructure configuration possible and does not need any self-made code, all implementations are provided by the framework.

Spring Batch Job Definition

The Job definition - for this tutorial - is quite short:

<job id="helloWorldJob">
    <step id="helloWorldStep" >
        <tasklet ref="helloWorldTasklet" />
    </step>
</job>
<bean id="helloWorldTasklet" 
      class="de.langmi.spring.batch.tutorials.helloworld.HelloWorldTasklet" />

In contrast to the introduction of the basic concepts, we use a so called Tasklet Step, without the standard Reader, Processor and Writer. A Tasklet Step bypasses the standard Step concept and makes it possible to implement just one method, like printing out Hello World!.

Complete XML

All XML taken from the configurations above and joined in one file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/batch 
       http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
       http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <description>
        Simple Spring Batch Configuration
        
        - one tasklet step
          - prints out "Hello World!"
        - setup without database, uses in-memory JobRepository
        - not restartable
    </description>
    
    <!-- 
        inline xmlns, otherwise it would look like 
        'batch:job, batch:step, etc.' 
    -->
    <job id="helloWorldJob" xmlns="http://www.springframework.org/schema/batch">
        <step id="helloWorldStep" >
            <tasklet ref="helloWorldTasklet" />
        </step>
    </job>

    <bean id="helloWorldTasklet" 
          class="de.langmi.spring.batch.tutorials.helloworld.HelloWorldTasklet" />
    
    <bean id="jobLauncher" 
          class="org.springframework.batch.core.launch.support.SimpleJobLauncher"
          p:jobRepository-ref="jobRepository" />
    
    <bean id="jobRepository" 
          class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"
          p:transactionManager-ref="transactionManager" />
    
    <bean id="transactionManager" 
          class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
</beans>

Java Code

In the Job configuration we configured a Tasklet Step, here is the missing source-code:

package de.langmi.spring.batch.tutorials.helloworld;

import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;

public class HelloWorldTasklet implements Tasklet {

    /** {@inheritDoc} */
    @Override
    public RepeatStatus execute(StepContribution contribution, 
                                ChunkContext chunkContext) throws Exception {

        // why not using println? because it makes testing harder, *nix and
        // windows think different about new line as in \n vs \r\n    
        System.out.print("Hello World!");

        return RepeatStatus.FINISHED;
    }
}

And that's it, yes really that and the configuration is a complete Spring Batch.

Testing

Before the batch escapes will be released it needs some tests.

Testing The Tasklet Step

The Tasklet implementation is pure Java, so we can test it as that with JUnit:

public class HelloWorldTaskletTest {

    private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();
    private final Tasklet tasklet = new HelloWorldTasklet();

    @Test
    public void testExecute() throws Exception {
        tasklet.execute(null, null);
        assertEquals("Hello World!", outContent.toString());
    }

    @Before
    public void setUpStreams() {
        // catch system out
        System.setOut(new PrintStream(outContent));
    }

    @After
    public void cleanUpStreams() {
        // reset JVM standard
        System.setOut(null);
    }
}

Testing Complete Job

To test the complete Job we can use a lot of the Spring JUnit test utilities. The only difference to a standard Spring test is the use of the Job Launcher, which is needed to launch a job.

@ContextConfiguration(locations = {"classpath*:spring/batch/job/hello-world-job.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class HelloWorldJobConfigurationTest {

    @Autowired
    private Job job;
    @Autowired
    private JobLauncher jobLauncher;
    private final ByteArrayOutputStream outContent = new ByteArrayOutputStream();

    /** Simple Launch Test. */
    @Test
    public void launchJob() throws Exception {
        // launch the job
        JobExecution jobExecution = jobLauncher.run(job, new JobParameters());

        // assert job run status
        assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());

        // assert sysoutput
        assertEquals("Hello World!", outContent.toString());
    }

    @Before
    public void setUpStreams() {
        // catch system out
        System.setOut(new PrintStream(outContent));
    }

    @After
    public void cleanUpStreams() {
        // reset JVM standard
        System.setOut(null);
    }
}

This test is essentially an integration test.

Run The Spring Batch Job

To run a Spring Batch Job one can use Spring Batch Admin, which is really out of scope for this tutorial, so we will use the standard Java Main-Class concept with an executable JAR.

Which Main Class ?

The nice thing about Spring frameworks is, right when you need a ready-to-use implementation, the framework has it. We need a Main Class, which can be configured easily and starts the job, here it is: CommandLineJobRunner.

The only thing left is an executable JAR, to create one the pom.xml from the tutorial sources has a configuration for the Maven-shade Plugin. To use it just run the usual: mvn clean install and there will be an hello-world-java-1.0-executable.jar ready for use.

Run It!

It's about time to end this tutorial, so here is the code to run the job:

java -jar hello-world-java-1.0-executable.jar spring/batch/job/hello-world-job.xml helloWorldJob

If all worked well, you see now a friendly Hello World!.

Conclusion

By following this tutorial you learned some Spring Batch basic concepts and built a simple Hello World! program. The next tutorials will cover more advanced concepts like Read, Process, Write or Logging.

Did you know?

Spring Batch was first introduced in 2007. Back then the framework was created by Interface21 - now known as Springsource - and Accenture. It has seen only 2 major versions so far, but the transition from version 1 to 2 included a massive refactoring of the core concepts. In fact the chunk oriented processing concept was first introduced with Spring Batch version 2.

Meta

Maven, Buildr, Gradle and Friends

I provided some build manager configurations for:

Each configuration file contains informations on used versions and general setup.

If you work without a build manager you can download all needed libraries from Spring Batch downloads, but remember this tutorial is tested with Spring Batch Version 2.1 only.