Blog4Java

A personal and Java blog, likely only for me

Introduction to Spring Batch. Part II: more on running a Job

| 0 comments

In the previous blog post entry, we introduced Spring Batch with a simple exposition of its features, main concepts both for configuring and running Batch Jobs.

We also saw a sample application and two ways of running it: by invoking a JobLauncher bean or by using CommandLineJobRunner from the command line.

In this blog entry, we’ll see two additional ways to run a Spring Batch job:

  1. Using JobOperator, in order to have control of the batch process, from start a job to monitoring tasks such as stopping, restarting, or summarizing a Job. We’ll only pay attention to the start operation, but once a JobOperator is configured, you can use for the remaining monitoring tasks.
  2. Using Spring Boot, the new convention-over-configuration centric framework from the Spring team, that allows you to create with a few lines of code applications that “just run”, because Spring Boot provides a lot of features based on what you have in your classpath.

As usual, all the source code is available at GitHub.

Running the sample: JobOperator

JobOperator is an interface that provides operations for inspecting and controlling jobs, mainly for a command-line client or a remote launcher like a JMX console.

The implementation that Spring Batch provides, SimpleJobOperator, uses JobLauncher, JobRepository, JobExplorer, and JobRegistry for performing its operations. They are created by the @EnableBatchProcessing annotation, so we can create an additional batch configuration file with these dependencies autowired and later import it in the batch configuration file (not without issues, due to the way Spring loads the application context, we’ll see this shortly):

And the @Import:

Now it seems easy to run the job with a main class:

But there’s a little problem… it doesn’t work:

The problem here, No job configuration with the name [importUserJob] was registered, is due to the way that JobOperator.start(String jobName, String parameters) works.

The main difference with JobLauncher.run(Job job, JobParameters jobParameters) is that the former has String as parameters while the latter uses objects directly.

So JobOperator, actually SimpleJobOperator, has to obtain a Job with the provided name. In order to do so, it uses the JobRegistry.getJob(String name) method. The available Spring Batch implementation is MapJobRegistry that uses a ConcurrentMap to store using the job name as the key, a JobFactory to create the Job when requested.

The problem is that this map has not been populated.

The first solution is easy: the JobRegistry allows you to register at runtime a JobFactory to later obtain the Job as explained above. So, we only need to create this JobFactory…

…and register it in the main method:

And now it works:

But I don’t like this approach, it’s too manual.

I’d rather to populate the JobRegistry automatically, and Spring Batch provides two mechanisms for doing so, a bean post-processor, JobRegistryBeanPostProcessor, and a component that loads and unloads Jobs by creating child context and registering jobs from those contexts as they are created, AutomaticJobRegistrar.

We’ll see the post-processor approach, because it’s very easy. Just declare the bean in the Batch configuration and run the original main class.

The bean post processor has to be declared in this configuration file for registering the job when it’s created (this is the issue that I mentioned before, if you declare the post processor in another java file configuration, for instance in the AdditionalBatchConfiguration it will never receive the job bean). It uses the same JobRegistry that uses the JobOperator to launch the Job. Actually the only that exists, but it’s good to know this.

It also works:

Running the sample: Spring Boot

We’d like to try how quickly and easy is Spring Boot for launching Spring Batch applications once we already have a functional configuration.

And it seems to be a piece of cake (the problem here is to know what is happening under the hood)

Actually, Spring Boot is out of the bounds of this topic, it deserves its own entry (even, an entire book) but we can summarize the important code here:

  • Line 3: @EnableAutoConfiguration, with this annotation you want Spring Boot to instantiate the beans that you’re going to need based on the libraries on your classpath.
  • Line 8: the run method, to bootstrap the application by passing the class itself (in our case, MainBoot) that serves as the primary Spring component.

It’s enough to run the Batch application:

As a side note, this class already scans for compontents, so we don’t need to make an additional scan for components, so we exclude the ApplicationConfiguration class with a filter.

Finally, we use the MainHelper class to show a summary of the results.

That’s all for now, because one more time this entry is growing really fast. Thus, we’ll see in the next post the last topic of Spring Batch that I want to talk about: JSR 352.

Resources

Author: Javier (@jbbarquero)

Java EE developer, swim addict, occasional videogames player, fan of Ben Alex and Shamus Young, and deeply in love with my wife. Sooner or later I'll dedicate a post to expand this simple introduction.

Leave a Reply

Required fields are marked *.