robots

Spring Batch es un software Open Source para procesar, tratar o integrar grandes cantidades de información en entornos de producción críticos.
Creado y mantenido en su mayor parte por Pivotal y Accenture, al ver que la comunidad ponía mayor énfasis en la creación de frameworks Web MVC.

Diseñado para ser fácil de utilizar, ligero y extensible, cuenta además con muchas funciones, como obtener estadísticas sobre las tareas programadas, reutilizar código, reinicio de tareas etc.

Elementos principales

Mediante un ejemplo en el que leeremos datos sobre hoteles en un fichero y los guardaremos en una base de datos H2, vamos a ir recorriendo los elementos principales que componen una tarea programada.

Job

Un “Job” es una entidad que engloba un proceso Batch completo.
Ésta entidad contiene:
– JobInstance: Es la instancia de la tarea que queremos ejecutar. Si por ejemplo tenemos programada la ejecución de una tarea cada lunes a las 00:00, si por cualquier motivo ésta falla, la próxima vez se volverá a ejecutar la misma instancia.
– JobParameters: Cada JobInstance cuenta con sus parámetros propios que la diferencian del resto.
– JobExecution: Se refiere a la ejecución de nuestra tarea programada. JobExecution contiene los parámetros de configuración de la tarea programada mas importantes como: startTime, endTime o failureExceptions.
Una tarea programada no se considerará como ejecutada correctamente hasta que su JobExecution quede en estado completado.

En nuestro ejemplo crearemos un Job llamado “importHotelJob” con un id auto incremental. Le añadiremos un listener para que una vez completado, capturemos el evento y ejecutemos una acción. Este Job contará con un único Step.

@Bean
public Job importHotelJob(JobCompletionNotificationListener listener, Step step1) {
    return jobBuilderFactory.get("importHotelJob")
        .incrementer(new RunIdIncrementer())
        .listener(listener)
        .flow(step1)
        .end()
        .build();
}

Step

Un Step es un objeto que engloba una fase de una tarea programada.
Cada Job contiene como mínimo al menos un Step, que puede consistir en una simple ejecución de una sentencia SQL o procedimientos con reglas de negocio mas complejas. Cada StepExcecution por ende está ligado a un JobExecution.

Crearemos un Step mediante un stepBuilderFactory, al que le asignaremos un reader, un writer y un processor.

@Bean
public Step step1(JdbcBatchItemWriter<Hotel> writer) {
    return stepBuilderFactory.get("step1")
        .<Hotel, Hotel> chunk(10)
        .reader(reader())
        .processor(processor())
        .writer(writer)
        .build();
}

ExecutionContext

Estructura de tipo clave – valor que permite guardar valores accesibles desde nuestros JobExecution y StepExecution.
Si por ejemplo nuestra tarea programada está leyendo un fichero, ésta puede guardar hasta que línea consiguió leer antes de fallar en ExecutionContext.

JobRepository

Provee de persistencia a nuestra tarea programada, proporcionando operaciones CRUD a los objetos Job y Step.
Al utilizar la anotación @EnableBatchProcessing estamos proporcionando un JobRepository a nuestra aplicación.

Si accedemos a la consola de H2 del ejemplo, podremos observar los elementos de Spring Batch comentados almacenados en base de datos.

ItemReader

Es una abstracción que se ejecutará en un Step y que representa la entrada de datos.

Para nuestro ejemplo en particular, ItemReader consiste en crear una instancia mediante el builder de FlatFileItemReader, en el que le indicaremos el archivo origen de los datos, los nombres de cada elemento y la clase utilizada como modelo.

@Bean
public FlatFileItemReader<Hotel> reader() {
    return new FlatFileItemReaderBuilder<Hotel>()
        .name("hotelItemReader")
        .resource(new ClassPathResource("hotel-reviews.csv"))
        .delimited().names(new String[]{"id", "address", "city", "country", "name"})
        .fieldSetMapper(new BeanWrapperFieldSetMapper<Hotel>() {{
            setTargetType(Hotel.class);
        }})
        .build();
}

ItemWriter

Al igual que ItemReader, ItemWriter es una abstracción que se ejecutará en un Step que representa una salida de datos.

Puesto que vamos a escribir datos en base de datos utilizaremos un JdbcBatchItemWriter, devolviendo una instancia de éste en la que se especifica la sentencia SQL que queremos ejecutar.

@Bean
public JdbcBatchItemWriter<Hotel> writer(DataSource dataSource) {
    return new JdbcBatchItemWriterBuilder<Hotel>()
        .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
        .sql("INSERT INTO hotel (id, address, city, country, name) VALUES (:id, :address, :city, :country, :name)")
        .dataSource(dataSource)
        .build();
}

ItemProcessor

Mientras que ItemReader nos permite leer e ItemWriter escribir, ItemProcessor nos permite aplicar un tratamiento personalizado a los datos y aplicar reglas de negocio particulares a cada necesidad.

En el caso de ejemplo, asignaremos los datos de hotel leídos en el fichero a una nueva instancia Hotel.

package com.juanmorschrott.hotel.batch;

import com.juanmorschrott.hotel.model.Hotel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.ItemProcessor;

public class HotelItemProcessor implements ItemProcessor<Hotel, Hotel> {

    private static final Logger log = LoggerFactory.getLogger(HotelItemProcessor.class);

    @Override
    public Hotel process(final Hotel hotel) throws Exception {
        final String id = hotel.getId();
        final String address = hotel.getAddress().toUpperCase();
        final String city = hotel.getCity().toUpperCase();
        final String country = hotel.getCountry().toUpperCase();
        final String name = hotel.getName().toUpperCase();

        final Hotel transformedHotel = new Hotel(id, address, city, country, name);

        log.info("Converting (" + hotel + ") into (" + transformedHotel + ")");

        return transformedHotel;
    }

}

Resultados

Al ejecutar la aplicación mediante:

./mvnw spring-boot:run

Veremos como se imprime en consola la ejecución del Job.
Si accedemos a la consola de H2 en http://localhost:8081/h2-console/ podremos ver como los datos están almacenados en base de datos.

Conclusión

Con un ejemplo sencillo hemos visto por encima algunos de los componentes principales de Spring Batch. Se puede decir que es por méritos propios el estándar de facto en la industria y una herramienta muy útil en el ámbito empresarial.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *