Vous êtes sur la page 1sur 23

Les presentamos Spring Batch

Sábado 06 de Septiembre de 2008 21:31 Escrito por Diego Gomez

Intentaremos hacer una introducción a Spring Batch, uno de los componentes de Spring mas
desconocidos hoy en día. No será esta una guía completa del framework, aunque pretendemos facilitar el primer contacto con este componente y
nombrar algunas de sus características. Aunque no nos resulte el trabajo mas excitante el escribir programas batch, siempre es necesario en los
trabajos tener claro como podríamos utilizar un framework para tal fin.

Ya hace unas semanas que jugamos un poco con el framework -sabrán que fue mas Leo que yo no...- aunque les cuento que leí casi toda la
funcionalidad que ofrecía el componente y llegue a entender el ejemplo que Leo me pasó y todo. En esas semanas pensabamos que teníamos un
proyecto 'justo' para este framework, que por razones de tiempo -y a veces de NO esfuerzo- no pudimos implementar en producción.

Antes de comenzar
Les cuento que soy una de esas personas que de los últimos diez años ha pasado casi seis haciendo programas batch -por suerte no fueron los últimos
seis, sino los primeros- y despues de estos últimos cuatro años sin hacer batch, la verdad que se me ponen los pelos de punta cuando me hablan de los
mismos. Programas en C, PRO*C monolíticos con miles de líneas de código, con un montón de código que se dejo de usar y da miedo sacar, con nada
de documentación y si MILES de líneas de código (5000, 7000)... o sea, difíciles de entender, de mantener, eso que ahora me molesta mas, antes
estaba acostumbrado.

Cuando empecé a leer la documentación, el primer pensamiento que se me vino a la mente fue 'Ufff, estos de Spring se pasaron de la raya con la
ingeniería de la librería, o con la sobreingeniería'.

Entonces con la lectura de la documentación hecha y con el ejemplo de Leo en mis narices, comencé a entender un poco mas que los de Spring no
habían pecado de sobreingeniería, y podemos decir entonces que Spring Batch no es un framework sino un esqueleto para desarrollar progamas Batch
de una manera simple, entendible y mantenible, y además tiene algunas implementaciones del esqueleto muy buenas.

Vamos entonces con Spring Batch en 2 palabras


Afortunadamente, el modelo de objetos que tiene Spring Batch lo explican los nombres por sí mismo. Vamos a tratar de enumerar los más importantes y
para vincularlos entre sí:

Un Job (Trabajo) se compone de uno o más Step's (Pasos). Un JobInstance representa un determinado Job, parametrizado con un conjunto de
propiedades llamados JobParameters. Cada ejecución de una JobInstance es una JobExecution. Imagine un trabajo de lectura de entradas de una base
de datos y la generación de un XML que represente la misma y, a continuación, haciendo algo para limpiarla.

Por ejemplo, pensemos un Job compuesto de 2 Step's: lectura / escritura y la limpieza. Si parametriza este Job por la fecha de los datos generados,
entonces nuestro Job del Viernes 13 es una JobInstance. Cada vez que ejecute este ejemplo (si se produce un error, para la instancia) es una
JobExecution. Este modelo ofrece una gran flexibilidad respecto a cómo los Job se inician y se ponen en marcha. Naturalmente, esto nos lleva a iniciar
sus trabajos con los parámetros de empleo, que es responsabilidad del JobLauncher. Por último, diversos objetos en el framework requieren un
JobRepository para almacenar en tiempo de ejecución información relacionada con la ejecución batch. De hecho, el modelo de dominio de Spring Batch
es mucho más elaborado pero esto será suficiente por ahora.

Writers, Readers o Transformers


Spring Batch viene por defecto con diferentes tipos de Readers para leer ficheros planos, XML o datos de base de datos. Estos Readers se configuran
con una especie de mapeo entre registros y objetos.

Por ejemplo, un archivo de planetas separado por comas, como el siguiente:


10,Mercurio,4879,rocoso,mensajero de los dioses
20,Venus,12103,telurico,diosa del amor y de la belleza
30,Tierra,12875,telurico,madre de todos los dioses
40,Marte,6794,telurico,dios de la guerra

Podría ser interpretado en objetos como:

public class Planeta {

private int codigo;

private String nombre;

private long diametro;

private String tipo;

private String significado;

....

Esos datos podrían por ejemplo ser transformados con cadenas de transformadores en base a diferentes reglas y
posteriormente almacenados utilizando un Writer a base de datos con su correspondiente mapeo entre los diferentes
campos y las columnas de una tabla que recoja esos datos.

Un Hola Mundo con Spring Batch


Vamos entonces a realizar el clásico "Hola, Mundo" con Spring Batch. Básicamente crearemos un Job que contendrá 3 Steps:

1. imprimir "Hola, "

2. imprimir "Mundo"

3. imprimir "!!!"

En código deberemos programar dos archivos:

• spring-batch-demo.xml, el contexto de Spring donde configuraremos Spring Batch, los Jobs y demás beans.

• ImprimirTasklet.java, que será la clase con la lógica para imprimir por consola un mensaje cualquiera.

Configuración básica
Por cada Job, vamos a utilizar un bean de Spring separado que lo representa. Hay también una serie de objetos comunes que vamos a necesitar
usualmente. Vamos a ir a través de estos objetos comunes:

JobLauncher

Los JobLaunchers son responsables de iniciar un trabajo con determinados parámetros. Existe una implementación prevista, SimpleJobLauncher, que
se basa en una TaskExecutor para poner en marcha los trabajos. Si no específico TaskExecutor, se setea entonces un SyncTaskExecutor para utilizarlo.

JobRepository

Un JobRepository es el encargado de almacenar información sobre la corrida de los Jobs.

Vamos a utilizar la implementación MapJobRepositoryFactoryBean que guarda la información de las ejecuciones en memoria.

En una implementación real, donde se quiere guardar en forma persistente esta información, se puede usar la implementación
JobRepositoryFactoryBean la cual utiliza una base de datos para almacenar toda la corrida. Spring Batch utiliza un modelo de datos con tablas propias
para este fin.
TransactionManager

No es un bean propio de Spring Batch, pero lo utiliza el JobRepository para manejar las transacciones. En este ejemplo, como no accederemos a ningún
medio transaccional, usaremos una implementación "dummy" del transaction manager ya provista por Spring Batch, llamada
ResourcelessTransactionManager.

Aquí está nuestro spring-batch-demo.xml

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

<bean id="jobRepository"
class="org.springframework.batch.
core.repository.support.MapJobRepositoryFactoryBean">
<property name="transactionManager" ref="transactionManager"/>
</bean>

<bean id="jobLauncher"
class="org.springframework.batch.
core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository"/>
</bean>
</beans>

Los tasklets del Hola Mundo


Un Tasklet es un objeto que contiene cualquier lógica que será ejecutada como parte de un trabajo. Los Tasklets se construyen mediante la
implementación de la interfaz Tasklet. Los Tasklet son la forma más simple en Spring Batch para ejecuar código.

Vamos a aplicar una tasklet que simplemente imprime un mensaje por consola:

public class ImprimirTasklet implements Tasklet {


private String mensaje;

public String getMensaje() {


return mensaje;
}

public void setMensaje(String mensaje) {


this.mensaje = mensaje;
}

public ExitStatus execute() throws Exception {


System.out.print(mensaje);
return ExitStatus.FINISHED;
}
}
Tengan en cuenta que al ejecutar el método devuelve un ExitStatus para indicar el estado de la ejecución de la Tasklet.

Vamos a definir nuestro primer Job ahora en el XML de la aplicación. Usaremos la implementación SimpleJob que ejecuta todos los pasos
secuencialmente. Con el fin de conectar un tasklet a un Job, necesitamos un TaskletStep.

Es decir, a continuación agregaremos a nuestra configuración anterior:

• un SimpleJob
• tres TaskletStep, que referencian a nuestros Tasklet
• tres Tasklet, configurados para imprimir distintos mensajes

<bean id="trabajoBatch" class="org.springframework.batch.core.job.SimpleJob">


<property name="steps">
<list>
<bean id="primerPaso"
class="org.springframework.batch.core.step.tasklet.TaskletStep">
<property name="jobRepository" ref="jobRepository"/>
<property name="tasklet" ref="imprimirHola" />
</bean>

<bean id="segundoPaso"
class="org.springframework.batch.core.step.tasklet.TaskletStep">
<property name="jobRepository" ref="jobRepository"/>
<property name="tasklet" ref="imprimirMundo"/>
</bean>

<bean id="tercerPaso"
class="org.springframework.batch.core.step.tasklet.TaskletStep">
<property name="jobRepository" ref="jobRepository"/>
<property name="tasklet" ref="imprimirExclamacion"/>
</bean>
</list>
</property>
<property name="restartable" value="true" />
<property name="jobRepository" ref="jobRepository" />
</bean>

<bean id="imprimirHola" class="com.dosideas.springbatch.demo0.ImprimirTasklet">


<property name="mensaje" value="Hola, " />
</bean>

<bean id="imprimirMundo" class="com.dosideas.springbatch.demo0.ImprimirTasklet">


<property name="mensaje" value="Mundo" />
</bean>

<bean id="imprimirExclamacion" class="com.dosideas.springbatch.demo0.ImprimirTasklet">


<property name="mensaje" value="!!!" />
</bean>

Ejecutando el Job
Ahora tenemos que hacer algo para poner en marcha la ejecución de nuestros Trabajos. Para esto crearemos un test JUnit que obtenga una instancia
del JobLauncher, e inicie una corrida del Job.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath:/com/dosideas/springbatch/demo0/spring-batch-demo.xml"
})
public class ImprimirHolaMundoTest {

@Autowired
private SimpleJobLauncher launcher;

@Autowired
private SimpleJob job;

@Test
public void iniciarJob() throws Exception {
JobParametersBuilder builder = new JobParametersBuilder();
builder.addDate("Ejecucion", new Date());
builder.addString("jobName", "Imprimir hola mundo por consola");
JobParameters parameters = builder.toJobParameters();

launcher.run(job, parameters);
}
}
Y listo! Este test ejecutará la tarea, y veremos por consola el mensaje "Hola, Mundo!!!".
Spring Batch también ofrece una clase conveniente para ejecutarse desde la línea de comandos: CommandLineJobRunner. En su forma más simple
esta clase tiene de 2 argumentos: el XML de contexto de la aplicación que contiene el Job para poner en marcha y el id de ese Job. Naturalmente,
requiere un JobLauncher que es configurado en el mismo XML.
A continuación se muestra cómo iniciar el trabajo desde la linea de comandos (necesita especificar el classpath):

java org.springframework.batch.core.launch.support.CommandLineJobRunner
spring-batch-demo.xml trabajoBatch

Curso de Spring Batch y descarga de un proyecto de ejemplo


Para ver más detalles pueden descargar el proyecto de ejemplo de Spring Batch. Esta descarga contiene el ejemplo aquí comentado en forma completa,
junto a varios ejemplos más que demuestran distintos aspectos de Spring Batch, y todas las librerias necesarias para su funcionamiento.

Además, publicamos el curso Procesamiento con Spring Batch, donde repasamos las distintas características de este framework y explicamos el
proyecto de ejemplo en detalle.

Adaptado libremente de Spring Batch Hello World.

Comentarios
El siguiente main() lo podés ubicar en la clase com.dosideas.springbatch.demo0.ImprimirTasklet :
public static void main(String[] args) throws Exception {
ApplicationCont ext context = new ClassPathXmlApp licationCont ext("classpath:/com/dosideas/springbatch/demo0/spring-batch-demo.xml");
SimpleJobLaunch er launcher = (SimpleJobLaunc h er) context.getBean("jobLauncher");
SimpleJob job = (SimpleJob) context.getBean("trabajoBatch");

JobParametersBu ilder builder = new JobParametersBu ilder();


builder.addDate("Ejecucion", new Date());
builder.addString("jobName", "Imprimir hola mundo por consola");
JobParameters parameters = builder.toJobParameters ();

launcher.run(job, parameters);
}

#7 leito 23-09-2008 18:12


Si tu pregunta es cómo iniciar el Job del \"hola mundo\" desde una clase de tu aplicación, es bastante simple.
En la clase de tu aplicación tenés que inyectar un SimpleJobLaunch er, y después ejecutar las mismas líneas que en el ejemplo de esta nota. Es decir, el
código para ejecutar el Job es el mismo desde un test o desde tu aplicación (siempre considerando que tu aplicación use Spring, sino vas a tener que
levantar Spring dentro de tu aplicación).
Si tenés más dudas te invito a seguirlo en el foro de Java (www.dosideas.com/foros.html?func=showcat&catid=2), que va a ser más claro.

#5 No puedo correr el test — 23-09-2008 07:05


Hola, corriendo el test de helloworld obtengo un:
org.springframework .beans.factory.BeanCreationExc eption: Error creating bean with name \'jobRepository\' defined in class path resource [spring-batch-
demo.xml]: Error setting property values; nested exception is org.springframework .beans.NotWritableProp ertyException: Invalid
property \'transactionMana ger\' of bean class [org.springframework .batch.core.repository.support.MapJobRepositor yFactoryBean]: Bean
property \'transactionMana ger\' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?

¿sabés que puede estar mal en el context?

#4 leito 18-09-2008 11:42


Fijate que en el proyecto de demo para descargar, en el paquete \"demo4\" hay justamente un ejemplo de lectura de una base de datos y escritura en un
archivo.

Recordá que si estás ejecutando desde un \"main\" tenés que iniciar el factory de Spring de manera adecuada (en el ejemplo de descarga, el factory se
inicia desde el mismo test JUnit).

#2 leito 09-09-2008 05:49


En el proyecto para descargar hay ejemplos más concretos con uso de archivos y bases de datos. Proximamente vamos a explicar más en detalle estos
ejemplos.

En todo caso, volviendo al \"Hola Mundo\", se podría modificar cada uno de los 3 pasos para que hagan cosas diferentes. Por ejemplo, el primer paso
podría leer un archivo y subirlo a una tabla, el segundo paso podría transformar estos datos de la tabla, y el último paso podría ordenar estos datos con
un query y guardarlos en un archivo de texto nuevamente.
Procesamiento con Spring Batch 2.0
Spring Batch es el framework para procesamiento de lotes de Spring Framework. Este
framework apunta a crear una plataforma que brinde servicios comunes para los
programas batch.

Este curso es una guía para ir aprendiendo las diferentes características de Spring
Batch 2.0, partiendo de ejemplos concretos.

Toda esta guía se basa en torno a un proyecto con ejemplos de Spring Batch, el cual
contiene distintos casos de uso. Iremos explicando cada caso por separado.

Durante el curso veremos:

• Conceptos básicos de Spring Batch.


• Un primer Hola Mundo con Tasklets.
• Lectura de archivos.
• Escritura en archivos.
• Lectura de base de datos.
• Transformación de datos.

Dudas y consultas
Realizá todas las consultas que necesites en el foro "Java" de Dos Ideas. ¡Siempre va a haber alguien para darte una mano!

Configuración del proyecto


Antes de comenzar descargaremos el proyecto de ejemplo (el cual contiene además todas las librerias necesarias) y configuraremos la base de
datos que usaremos durante el curso.

Sobre el proyecto de ejemplo


El proyecto de ejemplo para descargar está dividido en paquetes independientes llamado demo0, demo1, demo2, demo3, etc. Cada paquete es
independiente y contiene todas las clases y archivos de configuración para funcionar.

1A su vez, cada paquete demo tiene asociado un test JUnit que lo ejecuta. Los fuentes se encuentran en el directorio src y los tests en el directorio
test.

Cada demo es un ejemplo autocontenido que utiliza distintas funciones de Spring Batch. En los siguientes capítulos vamos a ir avanzando por
cada una de estos paquete demo, explicando en detalle los conceptos nuevos y su funcionamiento.

• Proyecto de ejemplo de Spring Batch archivo

• Configuración del entorno Recurso

Demo #0: Hola Mundo


2

Spring Batch es un framework para el procesamiento por lotes (o ejecuciones "batch"). Spring Batch provee:

• un marco general para la creación de programas batch.


• almacenamiento de la información de ejecuciones.
• utilización de conceptos conocidos para el procesamiento batch (Job, Step, JobInstance, JobExecution).
• utilidades para realizar acciones comunes en procesamietos batch (lectura/escritura de archivos, acceso a base de datos, etc).
Los conceptos principales de Spring Batch son:

• Job: representa un trabajo a ejecutar. Es el trabajo batch. Está compuesto de uno o más Step (pasos), los cuales se ejecutan
secuencialmente.

• Step: es un paso dentro de un Job. Representa una acción dentro de todo el Job. Un step puede leer un archivo, escribir en una base
de datos, realizar una transformación, etc.

• JobRepository: es un repositorio donde se almacenan las ejecuciones de los Job. Usualmente es una base de datos con tablas
propias de Spring Batch.
En el recurso siguiente vas a encontrar más información sobre estos conceptos básicos, y una explicación de la demo0 del proyecto.

• Conceptos básicos y demo0: Hola Mundo archivo

• Spring Batch en la wiki de Dos Ideas archivo

Demo #1: lectura de archivos


En el paquete "demo1" veremos como poder leer un archivo de texto separado por comas (archivo "planetas.csv"), y transformaremos cada línea
a un objeto que la represente. Luego imprimiremos ese objeto por consola.

Las clases

Para esto deberemos desarrollar dos clases:

• Planeta, que representa cada una de las líneas del archivo.

• ConsolaItemWriter, el cual imprime por consola un objeto Planeta.

La configuración
3

En el archivo de configuración spring-batch-demo.xml se ecuentra toda la configuración necesaria para Spring Batch. Los beans importantes
declarados en este archivo:

• jobRepository, que será el repositorio para las ejecuciones de nuestra tarea. Este bean registrará en la base de datos información
sobre la corrida.

• trabajoBatch, que es el Job (Trabajo) en cuestión. Hace referencia a un único Step (Paso), llamado imprimirPorConsola. El bean
imprimirPorConsola contiene un lector de items (itemReader) y un procesador de items (itemWriter).

• planetaItemReader, que será el encargado de leer el archivo de texto separado por comas, y transformar cada línea a un objeto
Planeta. El bean planetaFieldSetMapper indica que se usará la clase Planeta para transformar cada línea del archivo.

• consolaItemWriter, que será el encargado de procesar cada una de las líneas convertidas a Planeta por planetaItemReader.

El test ubicado en el paquete demo1 ejecuta esta tarea.

Demo #2: transformación de archivos


4

En el paquete demo2 veremos cómo leer un archivo de texto y realizar una transformación sobre cada una de las líneas, para generar un nuevo
archivo resultante.
Las clases
Para esta solución se programan dos clases:

• Planeta, que representa cada una de las líneas del archivo.

• PlanetaFieldSetCreator, que se encargará de transformar un objeto Planeta en una linea nueva para el archivo resultante.

La configuración
En el archivo de configuración spring-batch-demo.xml del paquete se ecuentra toda la configuración necesaria para Spring Batch. Los beans
importantes declarados en este archivo:

• convertirArchivo, el cual es un paso que tiene un lector de items (itemReader) y un procesador de items (itemWriter).

• planetaItemReader, que es un ItemReader que se encarga de leer el archivo de origen y convertir cada línea en un objeto Planeta.

• archivoPlanoItemWriter, que es un ItemWriter que se encargará de tomar un Planeta y convertirlo a una línea de este archivo. Para
hacer esto utiliza un fieldSetCreator creado por nosotros: la clase PlanetaFieldSetCreator.

Demo #3: acceso a una base de datos


En la demo del paquete demo3 encontraremos cómo acceder a una base de datos utilizando un query SQL, convertir cada fila del resultado en un
objeto y finalmente imprimirlo por consola.

Las clases

Para esto deberemos desarrollar dos clases:

• Planeta, que representa cada una de las filas resultantes del query.

• ConsolaItemWriter, el cual imprime por consola un objeto Planeta.


5

La configuración

En el archivo de configuración spring-batch-demo.xml se ecuentra toda la configuración necesaria para Spring Batch. Los beans importantes
declarados en este archivo:

• trabajoBatch, que es el Job (Trabajo) en cuestión. Hace referencia a un único Step (Paso), llamado imprimirPorConsola. El bean
imprimirPorConsola contiene un lector de items (itemReader) y un procesador de items (itemWriter).

• planetaItemReader, que será el encargado de ejecutar un query y transformar cada una de las filas en un objeto Planeta.

• consolaItemWriter, que será el encargado de procesar e imprimir por consola cada uno de los Planeta creados por
planetaItemWriter.

Demo #4: exportando una tabla hacia archivo


6

En la demo del paquete demo3 encontraremos cómo acceder a una base de datos utilizando un query SQL, convertir cada fila del resultado en un
objeto y finalmente imprimirlo por consola.

Las clases

Para esto deberemos desarrollar dos clases:

• Planeta, que representa cada una de las filas resultantes del query.
• PlanetaFieldSetCreator, que se encargará de transformar un objeto Planeta en una línea nueva para el archivo resultante

La configuración

En el archivo de configuración spring-batch-demo.xml se ecuentra toda la configuración necesaria para Spring Batch. Los beans importantes
declarados en este archivo:

• trabajoBatch, que es el Job (Trabajo) en cuestión. Hace referencia a un único Step (Paso), el cual contiene un bean con un lector de
items (itemReader) y un procesador de items (itemWriter).

• planetaItemReader, que será el encargado de ejecutar un query y transformar cada una de las filas en un objeto Planeta.

• archivoPlanoItemWriter, que será el encargado de procesar cada uno de los Planeta leídos por planetaItemReader y generar una
línea en el archivo de texto resultante.

Demo #5: integración con Compass y Lucene


Esta demo consta de dos steps, el primero “guardarIndice” donde se obtienen los registros de la tabla PLANETA, se convierte cada uno en un
objeto planeta y por ultimo se crea el índice lucene que contendrá la información de los objetos. El segundo “leerIndice” realiza una búsqueda en
el índice e imprime el resultado por pantalla.

Las clases

Las clases destacadas para esta demo son:

• Planeta, que representa cada una de las filas resultantes del Query y contiene las anotaciones de compass que nos permiten
persistir y consultar la misma en los índices lucene.

7 • CompassItemWriter, que contiene el método que persiste cada objeto planeta en el índice lucene.

• IndiceItemReader, que contiene el método que realiza las consultas en los índices aplicando paginación.

La configuración

En el archivo de configuración spring-batch-demo.xml se encuentra toda la configuración necesaria para Spring Batch. Beans importantes
declarados en este archivo:

• planetaItemReader, donde definimos el Query y el mapeo de la clase Planeta.

• Compass, es la factory de compass que nos permitirá trabajar con los índices.

• planetaItemWriter y indiceItemReader, ambos están creados con clases que extienden de CompassDaoSupport y es por esto que
se les injecta la factory de compass.

Demo #6: Manejo de excepciones


8

La demo del paquete demo6 amplía la demo1 (lectura de archivo e impresión por consola), considerando que algunas líneas del archivo de
entrada podrían ser incorrectas desde el punto de vista del formato y ese no debería ser motivo para finalizar el job, sino que se debería continuar
con la siguiente línea del archivo. Es importante tener en cuenta que cualquier exception lanzada durante la ejecución del job por defecto corta la
ejecución del mismo.

Las clases

La única clase destacada para esta demo es:

• PlanetaItemListener. Por extender de la clase de spring batch ItemListenerSupport, en esta clase nos vemos obligados a
implementar métodos abstractos para las acciones a seguir en caso de error en el reader, en el procesor y en el writer. Este listener
es entonces un handler de los errores que sucedan durante la ejecución del job. En la demo sólo se imprime un warning por consola
con las líneas del archivo que no pudieron ser parseadas correctamente.

La configuración

En el archivo de configuración spring-batch-demo.xml se ecuentra toda la configuración necesaria para Spring Batch. Beans importantes
declarados en este archivo:

• imprimirPorConsola, notemos que en esta demo para el step no estamos utilizando la implementación más básica de spring batch
(SimpleStepFactoryBean) como en las demos anteriores. En su lugar estamos utilizando una implementación más compleja:
FaultTolerantStepFactoryBean, que provee funcionalidad muy interesante para el manejo de fallos. Algunos de los atributos que
pueden setearse son:

○ noRollbackExceptionClasses, indica la lista de excepciones “permitidas”: aquellas para las cuales no se corta la
ejecución del job, sino que se continúa con el siguiente item sin realizar un rollback del chunk que se está procesando.

○ skipLimit, cantidad máxima de items que podrán saltearse debido a las excepciones “permitidas”.

○ listeners, lista de listeners asociados al step. En el ejemplo se ha desarrollado un listener como handler de errores
(PlanetaItemListener). Spring batch provee otros tipos de listeners que podemos implementar, como ItemReadListener,
que nos lleva a definir acciones a realizar antes del reader, después del reader y en caso de fallo en el reader. Para más
información consultar la API de Spring Batch.

Demo #7: ejecución en multihilos


La demo del paquete demo5 es básicamente la misma que la del paquete demo1 (lectura de archivo e impresión por consola), con el mismo
código Java, pero con la incorporación de una ejecución concurrente por configuración. La cantidad de hilos que se ejecutan se configura en el
Step (paso).

Las clases

Para esto deberemos desarrollar dos clases:

• Planeta, que representa cada una de las filas resultantes del query.

• PlanetaFieldSetCreator, que se encargará de transformar un objeto Planeta en una línea nueva para el archivo resultante
9

La configuración

En el archivo de configuración spring-batch-demo.xml se ecuentra toda la configuración necesaria para Spring Batch. Los beans importantes
declarados en este archivo:

• trabajoBatchMultithread, que es el Job (Trabajo) en cuestión. Hace referencia a un único Step (Paso), el cual contiene un bean con
un lector de items (itemReader) y un procesador de items (itemWriter). Además, e importante, este Step tiene configurado un
taskExecutor, en el cual se indica que este step será ejecutado por 3 hilos concurrentes.

• planetaItemReader, que será el encargado de ejecutar un query y transformar cada una de las filas en un objeto Planeta.

• archivoPlanoItemWriter, que será el encargado de procesar cada uno de los Planeta leídos por planetaItemReader y generar una
línea en el archivo de texto resultante.

Demo #8: procesamiento de datos


1

La demo del paquete demo8 contiene un ejemplo para realizar procesamiento de datos. A veces es necesario manipular los datos luego de ser
0
leídos y antes de escribirlos en el destino. Para esto se utiliza la interfaz ItemProcessor, que recibe un objeto leído y devuelve un objeto
procesado.
El ItemProcessor se agrega como atributo de un Step (paso).

Las clases

Para esto deberemos desarrollar dos clases:

• Planeta, que representa cada una de las filas resultantes del query.

• PlanetaItemReader, que se encargará leer planetas de la tabla en una base de datos, devolviendo un objeto Planeta por cada fila.

• PlanetaProcessor, que recibe un Planeta (leído por el PlanetaItemReader) y lo procesa, pasándo a mayúsculas sus atributos.

• PlanetaItemWriter, que recibe un Planeta procesado (por el PlanetaProcessor) y lo muestra por consola.

La configuración

En el archivo de configuración spring-batch-demo.xml se ecuentra toda la configuración necesaria para Spring Batch. Los beans importantes
declarados en este archivo:

• pasarAMayusculas, es el PlanetaProcessor que se encarga de recibir un Planeta, procesos sus atributos (pasarlos a mayúsculas) y
devolver este Planeta procesado.

• imprimirPorConsola, que es el Step que se encarga de leer los planetas (itemReader), procesarlos (itemProcessor) y escribirlos por
consola (itemWriter).

Demo #9: leer archivos con cabecera y compartir datos entre etapas de
un Step
La demo del paquete demo9 contiene un ejemplo para leer archivos planos en los que se recibe una primera línea “cabecera” con datos
generales del archivo y/o comunes a todos los registros, y las siguientes líneas son los registros que deben ser procesados individualmente.

Además veremos cómo se comparte información entre el reader y el writer, utilizando el contexto del step.

Las clases

Para esto deberemos desarrollar dos clases:

1
• CabeceraHandler, maneja el registro cabecera, leyéndolo y creando con sus datos el objeto de tipo CabeceraArchivo que se

1 compartirá entre el reader y el writer. Para compartirlo lo guarda en el contexto del step. Este contexto lo setea spring-batch al
encontrar en un método la anotación @BeforeStep. Además es necesario que el bean esté declarado como listener en el step.

• ConsolaItemWriter, cuyo bean también está declarado como listener del step, utiliza en esta ocacion los datos de la cabecera para
imprimir por consola.

La configuración

En el archivo de configuración spring-batch-demo.xml se ecuentra toda la configuración necesaria para Spring Batch. Los beans importantes
declarados en este archivo:

• cabeceraHandler, es el CabeceraHandler que se encarga de manipular la cabecera y dejarla disponible para el writer.

• cabeceraArchivo, es el nuevo bean en el que se mapeará el registro cabecera.

Configuración del entorno


Configuración del IDE
Durante este curso usaremos NetBeans IDE 6.5 como IDE para desarrollo y entorno de ejecución.
• Descargar NetBeans IDE

Una vez descargado el proyecto de ejemplo, lo descomprimimos. Abrimos luego este proyecto con NetBeans 6.1

Configuración de la base de datos


Usaremos Derby como base de datos, la cual ya viene embebida en NetBeans.
A continuación crearemos una nueva base de datos, le insertaremos los datos necesarios, y comprobaremos su funcionamiento.
1. Iniciar NetBeans IDE
2. Abrir el proyecto de ejemplos.
3. Ir al menú Window > Services
4. En el nodo Databases seleccionar Java DB > click derecho > create database...

1. Database name: springbatch

2. User name: springbatch

3. Password: springbatch

4. Click en Ok.
Tenemos entonces la base de datos creada. Vamos a ejecutar los scripts para crear las tablas de Spring Batch y una tabla de ejemplo para el curso.
1. ir al menú Window > Files
2. Abrir la carpeta dosideas-spring-batch > scripts-sql

3. Ejecutamos el script schema-derby.sql:

1. Abrir el archivo schema-derby.sql

2. En el combo "connection" seleccionar la conexión a la base de datos creada anteriormente


( jdbc:derby://localhost:1527/springbatch )
3. Click en el ícono "Run SQL".

4. Ejecutamos el script demo.sql:

1. Abrir el archivo demo.sql

2. En el combo "connection" seleccionar la conexión a la base de datos creada anteriormente


( jdbc:derby://localhost:1527/springbatch )
3. Click en el ícono "Run SQL".
Con estos pasos tenemos todas las tablas creadas, y ya podemos comenzar a utilizar las demos del proyecto.

sábado 24 de mayo de 2008

Primeros pasos con Spring Batch


Hace un tiempo atrás José Miguel Selman publico en su blog el lanzamiento oficial de la versión 1.0 de Spring Batch y desde
aquella vez que he querido poder programar un simple ejemplo para meter mis manos en esta nueva funcionalidad que nos
ofrece la gente de “SpringSource”, pero por motivos de tiempo (trabajo, clases, JUG, proyectos de investigación,…..etc)
nunca he podido darme un tiempo, hasta hoy que me decidí a como de lugar programar mis primeras líneas en” Spring
Batch” (mas bien no jugar PS3 :-( …....pero bueno….Lost Planet puede esperar).

En “Spring Batch” un Job es un proceso que se encuentra compuesto por uno o más Step. Para construir
un Job utilizaremos una JobInstance, la cual nos permitirá definir un Job, asociándole un conjunto de
propiedades llamadas JobParameters. Cada ejecución de una JobInstance será una JobExcecution.
Por ejemplo, supongamos que necesitamos cada cierto periodo de tiempo leer un información de un
repositorio de datos (una base de datos, un chache, etc…), generar un archivo XML que represente a esa
información e insertar este una cola de mensajería JMS. Este conjunto de tareas sería un Job el cual estaría
compuesto de tres Step. Si además, parametrizamos este Job para que se ejecute cada cierto periodo de
tiempo (una hora por ejemplo), cada periodo de tiempo seria una JobInstance y cada vez que se ejecute
esta instancia (depende de la hora), sería una JobExecution. Este modelo propuesto por “Spring Batch”
permite a los desarrolladores una gran flexibilidad respecto a cómo nuestros Job serán lanzados y
ejecutados.
El responsable de ejecutar cada uno de los Job definidos, además del grupo de parámetros asociados a este
será el JobLauncher. Por último, en muchos casos, necesitaremos algún lugar donde poder almacenar
información en tiempo de ejecución relacionada con el proceso batch, para lo cual se utiliza un
JobRepository.
Para cada Job es recomendable utilizar un archivo XML de contexto diferente (ya veo un modulo de procesos
batch definido con Impala….full!!!). Sin embargo, necesitaremos un conjunto de beans que serán utilizados
por cada uno de estos Job. Estos objetos los agruparemos en el applicationContext.xml, los cuales serán
importados desde cada una de las definiciones de los Job.

Es Los objetos comunes son:


• JobLauncher: El cual será el responsable de iniciar un Job cargando cada uno de sus parámetros asociados. La
implementación más básica se encuentra proveida por la clase SimpleJobLauncher, la cual se soporta en un
TaskExecutor para iniciar cada uno de los Job. Si no se especifica el tipo de TaskExecutor se configurara un
SyncTaskExecutor por defecto.

• JobRepository: Para el manejo del repositorio utilizaremos un SimpleJobRepository, la cual requerirá un conjunto
de DAOs para almacenar la información.

• JobInstanceDAO, JobExecutionDAO y StepExecutionDAO: Estos DAO serán usados por el


SimpleJobRepository para almacenar información relacionada con la ejecución de los Job. Para esto, “Spring
Batch” provee dos tipos de implementación: basados en Map (se almacenan los datos en memoria) y en JDBC.

En el archivo applicactionContext.xml quedaria asi:


1. <beans xmlns="http://www.springframework.org/schema/beans" xsi="http://www.w3.org/2001/XMLSchema-
instance" schemalocation="http://www.springframework.org/schema/beans http://www.springframework.or
g/schema/beans/spring-beans-2.5.xsd">
2.

3. <!-- DEFINICION DEL REPOSITORIO PARA LOS JOB -->

4. <bean id="jobRepository" class="org.springframework.batch.core.repository.support.SimpleJobRepository">

5. <constructor-arg>

6. <bean class="org.springframework.batch.core.repository.dao.MapJobInstanceDao">

7. </constructor-arg>

8. <constructor-arg>

9. <bean class="org.springframework.batch.core.repository.dao.MapJobExecutionDao">

10. </constructor-arg>

11. <constructor-arg>

12. <bean class="org.springframework.batch.core.repository.dao.MapStepExecutionDao">

13. </constructor-arg>

14. </bean>

15.

16. <!-- DEFINICION DEL LANZADOR DE LOS JOB AL CUAL SE LE INJECTA EL REPOSITORIO -->

17. <bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">

18. <property name="jobRepository" ref="jobRepository">

19. </bean>

20.

21. </beans>
<constructor-arg>
<bean class="org.springframew ork.batch.core.repository.d
</constructor-arg>
</bean>

<!-- DEFINICION DEL LANZADOR DE LOS JOB AL CUAL SE LE


<bean id="jobLauncher" class="org.springframew ork.batch.c
<property name="jobRepository" ref="jobRepository">
</bean>

Para programar nuestro ejemplo, la clase deberá implementar la interfaz Tasklet. Dentro de esta clase
programaremos la lógica que deberá ejecutar un Job, que en nuestro caso será un mensaje por consola.

1. package cl.jug;

2.

3. import org.springframework.batch.core.step.tasklet.Tasklet;

4. import org.springframework.batch.repeat.ExitStatus;

5.

6. public class EjemploTasklet implements Tasklet {

7.

8. private String mensaje;

9.

10. @Override

11. public ExitStatus execute() throws Exception {

12. System.out.print(mensaje);

13. return ExitStatus.FINISHED;

14. }
15.

16. public void setMensaje(String mensaje) {

17. this.mensaje = mensaje;

18. }
19.
20. }

public ExitStatus execute() throw s Exception {


System.out.print(mensaje);
return ExitStatus.FINISHED;
}

public void setMensaje(String mensaje) {


this.mensaje = mensaje;
}

Fíjense que el método “execute” retorna un ExitStatus para indicar el estado de ejecución del Tasklet.
Ahora solo nos queda definir nuestro primer Job en un archivo de contexto que llamaremos
EjemploBasicoJob.xml. Dentro de este, utilizaremos la implementación de un SimpleJob la cual ejecutara
todos los Step secuencialmente. Para poder definir un Tasklet dentro de un Job, deberemos utilizar un
TaskletStep.

1. <beans xmlns="http://www.springframework.org/schema/beans" xsi="http://www.w3.org/2001/XMLSchema-


instance" schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/sc
hema/beans/spring-beans-2.5.xsd">
2.

3. <import resource="applicationContext.xml">

4.

5. <!-- DEFINICION DE CADA UNO DEL LOS PASOS A EJECUTAR -->

6. <bean id="paso1" class="cl.jug.EjemploTasklet">

7. <property name="mensaje" value="Ejemplo de Spring Batch - ">

8. </bean>

9.

10. <bean id="paso2" class="cl.jug.EjemploTasklet">

11. <property name="mensaje" value="http://www.jug.cl - ">

12. </bean>

13.

14. <bean id="paso3" class="cl.jug.EjemploTasklet">

15. <property name="mensaje" value="jcoronel@jug.cl">

16. </bean>

17.

18. <!-- DEFINICION DEL EJECUTOR DE LOS PASOS DE MANERA SECUENCIAL -->

19. <bean id="taskletStep" abstract="true" class="org.springframework.batch.core.step.tasklet.TaskletStep">

20. <property name="jobRepository" ref="jobRepository">

21. </bean>

22.

23. <!-- DEFINICION DEL JOB EL CUAL ESTA COMPUESTO DE TRES PASOS SECUENCIALES -->

24. <bean id="ejemploJob" class="org.springframework.batch.core.job.SimpleJob">

25. <property name="name" value="ejemploJob">

26. <property name="jobRepository" ref="jobRepository">

27. <property name="steps">

28. <list>

29. <bean parent="taskletStep">

30. <property name="tasklet" ref="paso1">

31. </bean>

32. <bean parent="taskletStep">

33. <property name="tasklet" ref="paso2">

34. </bean>
35. <bean parent="taskletStep">

36. <property name="tasklet" ref="paso3">

37. </bean>

38. </list>

39. </property>

40. </bean>

41.

42. </beans>
<beans xmlns="http://w w w .springframew ork.org/schema/bea

<import resource="applicationContext.xml">

<!-- DEFINICION DE CADA UNO DEL LOS PASOS A EJECUTAR


<bean id="paso1" class="cl.jug.EjemploTasklet">
<property name="mensaje" value="Ejemplo de Spring Batch -
</bean>

<bean id="paso2" class="cl.jug.EjemploTasklet">

“Spring Batch” provee muchas formas de ejecutar un Job. La más simple es utilizando la clase
CommandLineJobRunner, al cual se puede ejecutar desde línea de comandos y recibe como parámetros
iniciales el nombe del archivo de contexto XML donde está definido el Job y el nombre del bean del Job. En
mi caso lo estoy ejecutando desde Eclipse, así que solo necesitao crear una nueva “Java Application” y en
el “Main class” definir la clase CommandLineJobRunner.

Por último, se le debe pasar por parámetro el nombre del archivo XML de contexto donde se encuentra
definido el Job y el nombre del bean del Job.
Más información respecto a ejemplo más complejos lo pueden consultar en
http://static.springframework.org/spring-batch/spring-batch-docs/reference/html/execution.html.

Opinión sobre Spring Batch

Tenía pendiente desde hace unos días escribir algo sobre uno de los componentes de Spring más desconocidos: Spring Batch. Desde luego, Spring
Batch ni suena, ni es uno de los componentes más sexies o excitantes con los que uno se vaya a encontrar en su vida laboral, a fin de cuentas los
batches son una de esas cosas que cuando te la nombran ya se te ponen los pelos como escarpias; pero el caso es que es uno de esos frameworks
oscuros que hacen su labor.

Hace unas semanas, tuve la oportunidad de jugar, no dejó de ser un juego, con esta librería durante unos días, y la verdad es que tengo que reconocer
que quedé mucho más satisfecho de lo que me experaba. Me explico. Cuando uno se enfrenta a la página principal y de features del framework, uno se
queda con el sabor de boca de que está delante de algo en los que sus creadores se han pasado de rosca. "Overengineered para lo que quiero hacer",
es lo primero que pensé yo.

Aún así, conforme vas adentrándote en su documentación, y vas comprendiendo sus conceptos, y sobre todo conforme vas implementando algo de
código, te das cuenta de su modularidad. En especial en un mundo, el de los batches, donde literalmente "vale todo", y los programas tienden a ser los
más monolíticos, sucios, incomprensibles y difíciles de mantener por lo general que uno se pueda encontrar. Que conste que esto que pongo se basa
única y exclusívamente en mi experiencia laboral (que no es realmente muy amplia), pero es que siempre que me ha tocado lidiar con algún proceso
batch, siempre ha sido la parte que a todos nos daba miedo tocar. Tanto da que sea un proceso que realiza un cálculo de gestión de costes cada mes, o
un proceso que cierra cuentas de traders y envía informes a medianoche en Java, o un proceso que extrae noticias de fuentes cada cinco minutos y las
va procesando. Siempre es lo mismo. No sé que pasa que con este tipo de procesos periódicos, la cosa siempre se lía.

Por eso uno, después de desarrollar un pequeño batch con Spring Batch se da cuenta de que mmmm, quizás el diseño no sea excesivo, es más, por fin
creo que tengo delante de mi un batch realmente mantenible.

Si estáis pensando que Spring Batch es una librería cuyo uso sólo se aplica a aplicaciones bancarias que procesen enormes cantidades de registros a
medianoche, estáis equivocados. Esta es una herramienta realemente aplicable a un amplio número de procesos ya que se basa en unas abstracciones
muy generales. En mi opinión, Spring Batch no es realmente un framework si no un esqueleto de aplicación de procesado de datos. Y como tal, se
puede aplicar a muchos entornos y problemas.

Describiéndolo muy rápidamente, Spring Batch define lo que son Trabajos que a su vez están definidos en tareas:

<bean id="footballJob"
class="org.springframework.batch.core.job.SimpleJob">
<property name="steps">
<list>
<!-- Step Bean details ommitted for clarity -->
<bean id="playerload" parent="simpleStep" />
<bean id="gameLoad" parent="simpleStep" />
<bean id="playerSummarization" parent="simpleStep" />
</list>
</property>
<property name="restartable" value="true" />
</bean>

Spring Batch se encargará de ejecutar estos trabajos y tareas y de repetirlos si se ha producido un error y cosas así, pero también de lo que quizás sea
más importante: de guardar contabilidad de todo lo que ha pasado con estos trabajos y tareas en base de datos.
STATUS
JOB_INSTANCE_ID START_TIME END_TIME
JOB_EXECUTION_ID

FAILED
1 1 2008-01-01 21:00:23.571 2008-01-01 21:30:17.132

Así, por ejemplo si nuestro proceso batch fuera un demonio que lee noticias RSS de diferentes sitios web (por poner algo diferente a bancos y todo esto)
y las almacena en base de datos. Tendríamos un trabajo (o varios) con diferentes tareas que se encargarían de recoger las noticias y almacenarlas. Lo
genial de Spring Batch es que podríamos configurar estas tareas como repetibles en caso de error, y que Spring Batch iría rellenando la tabla que veis
arriba con los resultados de las diferentes ejecuciones. Sin ningún esfuerzo estamos obteniendo una enorme transparencia y monitorabilidad en nuestra
aplicación.

Bueno, para mi esto que he explicado es lo más importante. A mayores Spring Batch ofrece muchas más cosas. Por ejemplo, cada trabajo podrá utilizar
diferentes Writers, Readers o Transformers. Spring Batch viene por defecto con diferentes tipos de Readers para leer ficheros planos, XML o datos de
base de datos. Estos Readers se configuran con una especie de mapeo entre registros y objetos de modo que algo en principio complicado como:

ID,lastName,firstName,position,birthYear,debutYear
"AbduKa00,Abdul-Jabbar,Karim,rb,1974,1996",

será traducido en:

public class Player implements Serializable {

private String ID;


private String lastName;
private String firstName;
private String position;
private int birthYear;
private int debutYear;

Por obra y gracia de Spring Batch. Esos datos podrían por ejemplo ser transformados con cadenas de transformadores en base a diferentes reglas y
posteriormente almacenados utilizando un Writer a base de datos con su correspondiente mapeo entre los diferentes campos y las columnas de una
tabla que recoja esos datos.

En fin, que no quiero aburriros mucho, que realmente creo que la gente de Spring ha hecho un buen trabajo al recopilar patrones comunes en las
aplicaciones de manejo de datos, ofreciento artefactos para leer, tratar y almacenar estos datos, para ejecutar, parar, saltarse o repetir tareas sobre
estos datos, y para monitorizar el estado de las ejecuciones del proceso sobre estos datos. Todo este trabajo nos permite hacer aplicaciones de
tratamiento de datos, es decir aplicaciones batch, realmente mantenibles, aunque tenga el coste inicial de comprender y acostumbrarse al framework.

Spring Batch Example


JDBC Template Batch update example, In the tutorial we have discussed about batchUpdate() method of class
JdbcTemplate in Spring framework. The Batch update methods are used to executes multiple SQL updates query on a
single JDBC Statement. The example given below consists of the code to delete and update data of the table
Simultaneously.

context.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/lang
http://www.springframework.org/schema/lang/spring-lang-2.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://192.168.10.75:3306/komal"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="lobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler">
<property name="nativeJdbcExtractor" ref="nativeJdbcExtractor"/>
</bean>
<bean id="nativeJdbcExtractor"
class="org.springframework.jdbc.support.nativejdbc.CommonsDbcpNativeJdbcExtractor"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>

Main.java

ApplicationContext ac = new ClassPathXmlApplicationContext("context.xml", Main.class):-ApplicationContext is


the interface that is used to provide Bean factory methods for accessing application components. Here we Creates an
instance of this interface to access context.xml and Main.java.

DataSource source = (DataSource) ac.getBean("dataSource"):-Data source is an Interface which provides a way for
connecting to the physical data source. Here we created datasource for making connection to our xml document in which
we have declared the bean.

jt.batchUpdate(new String[]{"update employee set departement = 'Finance#'", "delete from employee where
EmployeeId =31" }):-With the use of this method we are executing two SQLquery simultaneously. This method executes
multiple Sql updates on a single JDBC statement.

import javax.sql.DataSource;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
class Main {
public static void main(String args[]) {
try {
ApplicationContext ac = new
ClassPathXmlApplicationContext("context.xml", Main.class);
DataSource source = (DataSource) ac.getBean("dataSource");
JdbcTemplate jt = new JdbcTemplate(source);
jt.batchUpdate(new String[]{"update employee set departement =
'Finance#'",
"delete from employee where EmployeeId =31"
});
System.out.println("Data updated successfully");
} catch (Exception e) {
e.printStackTrace();
}
}
}

Output of the program

Data updated successfully

BUILD SUCCESSFUL (total time: 2 seconds)

Table Table
before updation after updation

Monday, June 2, 2008

Spring Batch - Hello World


Este es un tutorial introductorio a Spring Batch. No provee una guía completa al framework pero facilita el
primer contacto. Spring Batch es completamente rico en functionalidades, y así es básicamente como
empecé a aprenderlo. Mantén en mente que solo estarás rasgando la superficie.

Antes de iniciar
Todos los ejemplos tendrán la noble tarea de imprimir "Hola Mundo!" aunque en diferentes maneras. Fueron
desarrolados con Spring Batch 1.0. Proveeré un proyecto Maven 2 y correré los ejemplos con Maven pero de
hecho no es un requerimiento trabajar con Spring Batch.

Spring Batch en 2 palabras


Afortunadamente, el modelo de objetos de Spring Batch tiene nombres autoexplicativos. Vamos a intentar
enumerar los más importantes y a ligarlos juntos:

Un Job batch está compuesto de uno o mas Steps. Una JobInstance representa un trabajo dado,
parametrizado con un conjunto de propiedades tipeadas llamadas JobParameters. Cada corrida de una
JobInstance es una JobExecution. Imagina un job leyendo entradas desde una base de datos y generando
una representación xml de ello y luego hacer alguna limpieza. Tenemos un Job compuesto de 2 pasos:
leer/escribir y limpiar. Si parametrizamos este job por la fecha de los datos generados entonces nuestro job
del Vienres 13 es una JobInstance. Cada vez que corramos esta instancia (por ejemplo si una falla ocurre) es
una JobExecution. Este modelo ofrece una gran flexibilidad con respecto a cómo los jobs sean lanzados y
corridos. Esto por ejemplo nos trae lanzar jobs con sus propios parametros de job, lo cual es responsabilidad
del JobLauncher. Finalmente, varios objecos en el framework requieren un JobRepository para almacenar
información de tiempo de ejecución relacionada a la ejecución batch. De hecho, el modelo de dominio de
Spring Batch es mucho más elaborado pero esto será suficiente para nuestros propósitos.

Bueno, toma más que 2 palabras and y me siento obligado a hacer una broma sobre ello, pero no la haré.
Así que vamos a movernos a la siguiente sección.

Objetos Comunes
Para cada job, usaremos un archivo xml de definición de contexto separado. Sin embargo hay un número de
objetos comunes que necesitaremos recurrentemente. Los agruparé en un applicationContext.xml el cual
será importado dentro de las definiciones del trabajo. Vamos a ver estos objetos comunes:
JobLauncher
Los JobLaunchers son responsables de iniciar un Job con unos parámetros de job dados. La implementación
proveida, SimpleJobLauncher, se basa en un TaskExecutor para lanzar los jobs. Si no lo especificamos
TaskExecutor es asignado entonces y se usa un SyncTaskExecutor.

JobRepository
Usaremos la implementación SimpleJobRepository la cual requiere un set de Daos de ejecución para
almacenar su información.

JobInstanceDao, JobExecutionDao, StepExecutionDao


Estos objetos de acceso a datos son usados por SimpleJobRepository para almacenar información
relacionada a la ejecución. Se proveen dos conjuntos de implementaciones por Spring Batch: Basadas en
Map (en-memoria) y basadas en Jdbc. En una aplicación real las variantes de Jdbc son más adecuadas pero
usaremos la alternativa en-memoria más simple en este ejemplo.

Aquí esta nuestro applicationContext.xml:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springfr
amework.org/schema/beans/spring-beans-2.5.xsd">

<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository"/>
</bean>

<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.SimpleJobRepository">
<constructor-arg>
<bean class="org.springframework.batch.core.repository.dao.MapJobInstanceDao"/>
</constructor-arg>
<constructor-arg>
<bean
class="org.springframework.batch.core.repository.dao.MapJobExecutionDao" />
</constructor-arg>
<constructor-arg>
<bean
class="org.springframework.batch.core.repository.dao.MapStepExecutionDao"/>
</constructor-arg>
</bean>

</beans>

Hola Mundo con Tasklets


Un tasklet es un objeto que contiene alguna lógica personalizada para ser ejecutada como parte de un job.
Los tasklets son construidos implementando la interfaz Tasklet. Vamos a implementar un simple tasklet que
solamente imprime un mensaje:

public class PrintTasklet implements Tasklet{

private String message;

public void setMessage(String message) {


this.message = message;
}

public ExitStatus execute() throws Exception {


System.out.print(message);
return ExitStatus.FINISHED;
}
}

Nota que el método execute retorna un ExitStatus para indicar el estatus de la ejecución del tasklet.

Definiremos nuestro primer job ahora en un contexto de aplicación simpleJob.xml. Usaremos la


implementación SimpleJob que ejecuta todos sus pasos secuencialmente. Con el fin de conectar un tasklet
en un job, necesitamos un TaskletStep. También agregué la definición de un bean abstracto para los pasos
del tasklet con el fin de simplificar la configuracion:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework
.org/schema/beans/spring-beans-2.5.xsd">

<import resource="applicationContext.xml"/>

<bean id="hello" class="helloworld.PrintTasklet">


<property name="message" value="Hello"/>
</bean>

<bean id="space" class="helloworld.PrintTasklet">


<property name="message" value=" "/>
</bean>

<bean id="world" class="helloworld.PrintTasklet">


<property name="message" value="World!"/>
</bean>

<bean id="taskletStep" abstract="true"


class="org.springframework.batch.core.step.tasklet.TaskletStep">
<property name="jobRepository" ref="jobRepository"/>
</bean>

<bean id="simpleJob" class="org.springframework.batch.core.job.SimpleJob">


<property name="name" value="simpleJob" />
<property name="steps">
<list>
<bean parent="taskletStep">
<property name="tasklet" ref="hello"/>
</bean>
<bean parent="taskletStep">
<property name="tasklet" ref="space"/>
</bean>
<bean parent="taskletStep">;
<property name="tasklet" ref="world"/>
</bean>
</list>
</property>
<property name="jobRepository" ref="jobRepository"/>
</bean>
</beans>

Corriendo el Job
Ahora necesitamos algo para poner en marcha la ejecución de nuestros jobs. Spring Batch provee una clase
conveniente para llevar a cabo eso desde la línea de comandos: CommandLineJobRunner. En su forma mas
simple toma 2 argumentos: el contexto de aplicación xml que contiene el job a lanzar y el id del bean de ese
job. Naturalmente requiere un JobLauncher para ser configurado enel contexto de la aplicación. Aquí está el
cómo lanzar el job con Maven. De hecho, puede ser corrido directamente con el comando java (entonces
necesitas especificar la ruta de la clase):

mvn exec:java
-Dexec.mainClass=org.springframework.batch.core.launch.support.CommandLineJobRunner

-Dexec.args="simpleJob.xml simpleJob"

Esperemos que, sus esfuerzos sean recompensados con un "Hola Mundo!" impreso en la consola.

El codigo fuente puede ser descargado aqui.

Escrito por Tareq Abed Rabbo

Traducido por Abimael Desales López

Vous aimerez peut-être aussi