Spring Framework 004 - Como ejecutar tareas periódicas en Spring

De ChuWiki

Para hacer que Spring ejecute periódicamente algunos de los métodos de nuestras clases, debemos indicarle scheduled-tasks en el fichero Spring XML de configuración o bien anotar los métodos de nuestras clases con la anotación @Scheduled

Vamos a hacer un ejemplo tanto con fichero de configuración XML de Spring como con anotaciones. Puedes verlo completo en ScheduledMain.java

Tareas periódicas[editar]

Lo primero es hacer en nuestra clase un método público, con el nombre que más nos guste, al que Spring llamará periódicamente. No hace falta meter ahí bucles o timers, Spring se encarga de ellos. Sólo debemos implementar lo que queremos que se haga en un instante concreto. Un ejemplo puede ser

public class ScheduledXMLSample {
    public void repeat(){
        System.out.println(getClass().toString() + ".repeat() llamado");
    }
}

Spring llamará a nuestro método repeat() periódicamente cada cierto tiempo, según lo configuremos. Podemos configurar Spring bien en el fichero XML, bien con una anotación en la clase. Veamos ambos casos.

task:scheduled-tasks[editar]

Para configurarlo en el fichero XML de Spring, tendríamos que poner algo así

<?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:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/task
           http://www.springframework.org/schema/task/spring-task-4.2.xsd">

    <bean id="scheduledXMLSample" class="com.chuidiang.pruebas.scheduled.ScheduledXMLSample"/>
    <task:scheduled-tasks>
        <task:scheduled ref="scheduledXMLSample" method="repeat" fixed-rate="2000"/>
    </task:scheduled-tasks>
</beans>

En el tag <beans> del principio hemos puesto una línea con xmlns:task y en la parte de xsi:schemaLocation hemos puesto un par de líneas relativas task. Esto nos permite usar las etiquetas task: en nuestro fichero Spring que nos permitirán configurar nuestras tareas periódicas.

Luego simplemente instanciar nuestro bean ScheduleXMLSample

Y finalmente, con <task:scheduled-tasks> empezamos nuestra lista de tareas periódicas. Podemos poner las que queramos, llamando a distintos métodos de distintas clases. En nuestro ejemplo, sólo llamaremos al método repeat() de la clase ScheduledXMLSample

Así que en la lista metemos un <task:scheduled>. En ref le pasamos el nombre de nuestro bean instanciado scheduledXMLSample, en method el método de ese bean al que tiene que llamar y luego podemos indicar cada cuanto llamarlo. Tenemos ahí varias opciones, incluso para poner a la vez, pero solo hemos usado una en el ejemplo

  • fixed-rate, la del ejemplo, nos dice cada cuanto llamar a ese método. En el ejemplo, 2000 ms, es decir, 2 segundos. Se hará esto independientemente de que la ejecución anterior haya terminado o no.
  • fixed-delay es similar a la anterior, pero espera el tiempo que se indique entre una ejecución y la siguiente. Es decir, entre ejecuciones puede pasar más tiempo de lo que diga el fixed-delay, porque hay que sumar el tiempo que tarda el método en ejecutarse.
  • cron. Aquí podríamos poner una expresión de [[1]], que nos permite cosas más complejas que ejecuciones cada x tiempo. Por ejemplo, con cron podemos poner que queremos ejecutar los días laborables (lunes a viernes) a las 12 de la mañana.
  • initial-delay. Podemos poner un tiempo de espera antes de la primera llamada periódica. A partir de ahí comenzarán las llamadas periódicas según hayamos indicado con alguna de las opciones anteriores.

Listo, si hacemos un main y ejecutamos, tendríamos algo como esto

class com.chuidiang.pruebas.scheduled.ScheduledXMLSample.repeat() llamado
class com.chuidiang.pruebas.scheduled.ScheduledXMLSample.repeat() llamado
class com.chuidiang.pruebas.scheduled.ScheduledXMLSample.repeat() llamado
...

Anotación @Scheduled[editar]

La otra opción, si nos gustan más las anotaciones, es anotar los métodos con @Scheduled. Esta anotación admite las mismas configuraciones que en el fichero XML de Spring. Nuestra clase quedaría

@Component
public class ScheduledAnnotatedSample {
    @Scheduled(initialDelay = 2000, fixedRate = 1000)
    public void repeat(){
        System.out.println(getClass().toString()+".repeat() llamado");
    }
}

Ningún truco especial, con @Component indicamos a Spring que instancie esta clase y con @Scheduled anotamos el método que queramos que se ejecute periódicamente. Esta vez le hemos puesto initialDelay de 2 segundos (2000 ms) y un fixedRate de 1 segundo (1000 ms)

En el fichero de Spring, debemos poner lo siguiente

<?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:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/task
           http://www.springframework.org/schema/task/spring-task-4.2.xsd">

    <context:component-scan base-package="com.chuidiang.pruebas.scheduled"/>
    <task:annotation-driven/>
</beans>

En la parte inicial, igual que en el caso anterior, todo lo necesario para poder usar las etiquetas task:. Con <context:component-scan> le indicamos a Spring en qué paquetes buscar clase para instanciar, es decir, con anotación @Component. Y con <task:annotation-driven> le indicamos a Spring que haga caso a las anotaciones @Scheduled en los métodos de esas clases que ha instanciado.

Y todo listo, haciendo un main y ejecutando

jun. 10, 2023 7:01:28 P. M. org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor finishRegistration
INFORMACIÓN: No TaskScheduler/ScheduledExecutorService bean found for scheduled processing
class com.chuidiang.pruebas.scheduled.ScheduledAnnotatedSample.repeat() llamado
class com.chuidiang.pruebas.scheduled.ScheduledAnnotatedSample.repeat() llamado
class com.chuidiang.pruebas.scheduled.ScheduledAnnotatedSample.repeat() llamado
class com.chuidiang.pruebas.scheduled.ScheduledAnnotatedSample.repeat() llamado

Tenemos un mensaje de INFO inicial que es un aviso de Spring indicando que no hemos definido ningún ejecutor de tareas, así que usará el que tiene por defecto. Podríamos crear uno nuestro propio para hacerle alguna configuración especial, pero es tema para otro tutorial.