Schedulare i job con Quartz e Spring
In questo tutorial vedremo come sia facile implementare la schedulazione dei job nei progetti che utilizzano Spring; vedremo in particolare come aggiungere queste funzionalità ad un progetto creato con Appfuse, un ottimo framework che permette di partire con un progetto già configurato e subito utilizzabile. Da provare!
1) Aggiunta delle librerie necessarie
Per prima cosa bisogna aggiungere le dipendenze necessarie al progetto. Per fortuna Appfuse utilizza Maven 2 per eseguire i build, quindi aggiungere una dipendenza si riduce ad aggiungere un riferimento nel file pom.xml.
Nella sezione <dependencies> bisogna aggiungere queste righe:
<dependency>
<groupId>opensymphony</groupId>
<artifactId>quartz-all</artifactId>
<version>1.6.0</version>
</dependency>
Attenzione alla versione: al momento della stesura di questo articolo quella da utilizzare è la 1.6.0, col tempo ovviamente cambierà. Fate sempre riferimento ai siti ufficiale di Quartz e AppFuse prima di cambiare questo valore.
2) implementazione
Il passo successivo è la creazione del nostro job da automatizzare. Alcuni esempi tipici potrebbero essere:
- job che osservano i file in una certa directory e li processano in blocco;
- job che vengono fatti eseguire di notte perché molto pesanti o perché devono girare quando altre applicazioni sono inattive;
- job che eseguono operazioni ad intervalli regolari.
Il nostro job sarà del primo tipo, lo chiameremo MyHappyFileImporter:
package megadix.quartz;
import java.io.File;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class MyHappyFileImporter {
private Log log = LogFactory.getLog(MyHappyFileImporter.class);
private File watchDirectory;
public void setWatchDirectoryPath(String watchDirectoryPath) {
this.watchDirectory = new File(watchDirectoryPath);
}
public void doPolling() {
log.info("Reading file list from + \"" + watchDirectory.getAbsolutePath() + "\"...");
String[] files = watchDirectory.list();
for (String name : files) {
log.info("Processing : " + name);
// TODO put actual processing code here :)
}
log.info("Finished processing files");
}
}
Come si può vedere la classe non ha dipendenze verso le librerie di Spring o Quartz, riducendosi ad un semplice JavaBean; questo in effetti è uno dei maggiori punti di forza di questa soluzione, cioè l'indipendenza dal sistema utilizzato per realizzare la schedulazione. In questo modo i componenti possono essere testati molto più semplicemente e ci permetterà un futuro di cambiare sistema di schedulazione.
Ovviamente è "finta", nel senso che il metodo principale (doPolling() nel nostro caso) si limita a scrivere nei log le operazioni senza eseguirle. Quello è compito vostro!
3) Configurazione di Spring
Bisogna ora dire al container di Spring come configurare il nostro job. Abbiamo già detto che la nostra implementazione sarà un semplice JavaBean, potremo quindi configurarlo senza particolari accorgimenti. Aprire il file src/main/webapp/WEB-INF/applicationContext.xml e aggiungere queste righe:
<bean id="myHappyFileImporterImpl" class="sample.quartz.MyHappyFileImporter"> <property name="watchDirectoryPath" value="C:/temp/tobedeleted" /> </bean>
Ricordatevi di modificare la property "watchDirectoryPath", deve indicare una directory realmente esistente nel vostro filesystem.
Ora dobbiamo dire a Quartz che per eseguire il nostro job deve invocare il metodo doPolling() sul bean "myHappyFileImporterImpl", che abbiamo appena configurato. Per fare ciò basta aggiungere queste righe:
<bean id="myHappyFileImporterJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="myHappyFileImporterImpl" /> <property name="targetMethod" value="doPolling" /> </bean>
Infine dobbiamo indicare un piano di schedulazione, ad esempio:
- partenza dopo 30 secondi dallo startup dell'applicazione;
- esecuzione ogni 60 secondi.
Per fare ciò possiamo usare i cosiddetti "trigger", presenti in due varianti: SimpleTrigger e CronTrigger. Spring fornisce un'implementazione per ognuno di essi, aggiungendo delle funzionalità.
In questo esempio vediamo come configurare un SimpleTrigger in modo che rispetti la schedulazione vista qui sopra:
<bean id="myHappyFileImporterTrigger_simple" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="myHappyFileImporterJob" /> <property name="startDelay" value="30000" /> <property name="repeatInterval" value="10000" /> </bean>
Per configurazioni molto più sofistate invece sarà necessario utilizzare un CronTrigger, ecco un esempio con diverse varianti:
<bean id="myHappyFileImporterTrigger_cron"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="myHappyFileImporterJob" />
<property name="cronExpression">
<!-- Esegui ogni dieci secondi
<value>0/10 * * * * ?</value>
-->
<!-- Esegui a mezzanotte, tutti i giorni
<value>0 * * * * ?</value>
-->
<!-- Esegui ogni dieci minuti al secondo zero, a partire dal minuto zero,
tutti i giorni
<value>0 0/10 * * * ?</value>
-->
<!-- Esegui ogni due ore a partire dalle 00:15, nell'ultimo giorno di
Gennaio, Aprile e Settembre
<value>0 15 0/2 L 0,3,8 ?</value>
-->
</property>
</bean>
E' chiaro che nel nostro file di configurazione metteremo normalmente solo una di queste implementazioni! Nulla vieta di mantenerle entrambe, ovviamente, nel nostro caso ci fa comodo averle entrambe sotto mano.
L'ultimo passo è la configurazione di un SchedulerFactoryBean, il vero e proprio "motore" che fa partire l'esecuzione dei job:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <!-- <ref local="myHappyFileImporterTrigger_simple" /> <ref local="myHappyFileImporterTrigger_cron" /> --> </list> </property> </bean>
Per attivare uno dei trigger bisogna estrarlo dal commento. E' possibile addirittura usarli entrambi, anche se non ha molto senso.
Per visualizzare i messagi di INFO sulla console o nei file di log è necessario attivare il livello di log nel file di configurazione di Log4j, che si trova in src/main/resources/log4j.xml:
<logger name="megadix.quartz.MyHappyFileImporter"> <level value="INFO" /> </logger>
Ora eseguite un build e il deploy dell'applicazione per osservare il vostro job in azione!
Links
- Sito ufficiale di Quartz:
http://www.opensymphony.com/quartz/ - Spring framework:
http://www.springframework.org/ - Appfuse:
http://appfuse.org/ - Maven:
http://maven.apache.org/ - Un articolo interessante sull'integrazione Appfuse-Quartz:
http://www.lucianofiandesio.com/javatales/qtzfuse.html
- dimitri's blog
- Aggiungi un commento
- 1361 letture

