diff --git a/README.adoc b/README.adoc index 1d74f70d93..96818dcb65 100644 --- a/README.adoc +++ b/README.adoc @@ -120,10 +120,20 @@ The first method defines the job and the second one defines a single step. Jobs In this job definition, you need an incrementer because jobs use a database to maintain execution state. You then list each step, of which this job has only one step. The job ends, and the Java API produces a perfectly configured job. +The `listener()` method lets you hook into the engine and detect when the job is complete, triggering the verification of results. + In the step definition, you define how much data to write at a time. In this case, it writes up to ten records at a time. Next, you configure the reader, processor, and writer using the injected bits from earlier. NOTE: chunk() is prefixed `` because it's a generic method. This represents the input and output types of each "chunk" of processing, and lines up with `ItemReader` and `ItemWriter`. +`src/main/java/hello/JobCompletionNotificationListener.java` +[source,java] +---- +include::/complete/src/main/java/hello/JobCompletionNotificationListener.java[] +---- + +This code listens for when a job is `BatchStatus.COMPLETED`, and then uses `JdbcTemplate` to inspect the results. + == Make the application executable diff --git a/complete/src/main/java/hello/Application.java b/complete/src/main/java/hello/Application.java index 47033b5f03..55927b607a 100644 --- a/complete/src/main/java/hello/Application.java +++ b/complete/src/main/java/hello/Application.java @@ -1,36 +1,12 @@ package hello; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.List; -import java.util.concurrent.CountDownLatch; - import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.context.ApplicationContext; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; @SpringBootApplication public class Application { public static void main(String[] args) throws Exception { - ApplicationContext ctx = SpringApplication.run(Application.class, args); - - CountDownLatch countDownLatch = ctx.getBean(CountDownLatch.class); - - countDownLatch.await(); - - List results = ctx.getBean(JdbcTemplate.class).query("SELECT first_name, last_name FROM people", new RowMapper() { - @Override - public Person mapRow(ResultSet rs, int row) throws SQLException { - return new Person(rs.getString(1), rs.getString(2)); - } - }); - - for (Person person : results) { - System.out.println("Found <" + person + "> in the database."); - } - + SpringApplication.run(Application.class, args); } } diff --git a/complete/src/main/java/hello/BatchConfiguration.java b/complete/src/main/java/hello/BatchConfiguration.java index fefa546d70..fc0c3341af 100644 --- a/complete/src/main/java/hello/BatchConfiguration.java +++ b/complete/src/main/java/hello/BatchConfiguration.java @@ -1,7 +1,5 @@ package hello; -import java.util.concurrent.CountDownLatch; - import javax.sql.DataSource; import org.springframework.batch.core.Job; @@ -29,16 +27,6 @@ import org.springframework.jdbc.core.JdbcTemplate; @EnableBatchProcessing public class BatchConfiguration { - @Bean - public CountDownLatch countDownLatch() { - return new CountDownLatch(1); - } - - @Bean - public JobExecutionListener jobExecutionListener(CountDownLatch countDownLatch) { - return new JobCompletionNotificationListener(countDownLatch); - } - // tag::readerwriterprocessor[] @Bean public ItemReader reader() { diff --git a/complete/src/main/java/hello/JobCompletionNotificationListener.java b/complete/src/main/java/hello/JobCompletionNotificationListener.java index 96f23ff2ad..a8c600c3c1 100644 --- a/complete/src/main/java/hello/JobCompletionNotificationListener.java +++ b/complete/src/main/java/hello/JobCompletionNotificationListener.java @@ -15,30 +15,52 @@ */ package hello; -import java.util.concurrent.CountDownLatch; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.JobExecution; import org.springframework.batch.core.listener.JobExecutionListenerSupport; -import org.springframework.util.Assert; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; /** * @author Michael Minella */ +@Component public class JobCompletionNotificationListener extends JobExecutionListenerSupport { - private CountDownLatch countDownLatch; + private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class); - public JobCompletionNotificationListener(CountDownLatch countDownLatch) { - Assert.notNull(countDownLatch); + private final JdbcTemplate jdbcTemplate; - this.countDownLatch = countDownLatch; + @Autowired + public JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; } @Override public void afterJob(JobExecution jobExecution) { if(jobExecution.getStatus() == BatchStatus.COMPLETED) { - countDownLatch.countDown(); + log.info("!!! JOB FINISHED! Time to verify the results"); + + List results = jdbcTemplate.query("SELECT first_name, last_name FROM people", new RowMapper() { + @Override + public Person mapRow(ResultSet rs, int row) throws SQLException { + return new Person(rs.getString(1), rs.getString(2)); + } + }); + + for (Person person : results) { + log.info("Found <" + person + "> in the database."); + } + } } } diff --git a/complete/src/main/java/hello/PersonItemProcessor.java b/complete/src/main/java/hello/PersonItemProcessor.java index 0752f5868b..78f30cfee1 100644 --- a/complete/src/main/java/hello/PersonItemProcessor.java +++ b/complete/src/main/java/hello/PersonItemProcessor.java @@ -1,9 +1,14 @@ package hello; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import org.springframework.batch.item.ItemProcessor; public class PersonItemProcessor implements ItemProcessor { + private static final Logger log = LoggerFactory.getLogger(PersonItemProcessor.class); + @Override public Person process(final Person person) throws Exception { final String firstName = person.getFirstName().toUpperCase(); @@ -11,7 +16,7 @@ public class PersonItemProcessor implements ItemProcessor { final Person transformedPerson = new Person(firstName, lastName); - System.out.println("Converting (" + person + ") into (" + transformedPerson + ")"); + log.info("Converting (" + person + ") into (" + transformedPerson + ")"); return transformedPerson; }