We have several Jobs running the business. At the moment they are implemented as Spring-driven TimerTasks. But the next job should be run only nightly and a cron-like configuration syntax would be fine.
So I found Quartz and had to integrate that. For getting familiar with Quartz+Spring I wrote a small proof of concept.
The job implementation is just a POJO with a public void method. It should not throw any exception. The bean can be configured via usual Spring DI:
public class MyBean { private String message; public void doIt() { System.out.println("Hello World: " + message); } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
So fine. But how to test? For this PoC a very simple test is ok – just wait for some Quartz run and check the output manually:
import static org.junit.Assert.assertNotNull; import org.junit.AfterClass; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class QuartzTest { @Test public void context() { System.out.println("Starting Spring and within that: Quartz"); ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml"); assertNotNull(ctx); } @AfterClass public static void sleep() throws InterruptedException { System.out.println("Wait for job output"); Thread.sleep(8000); System.out.println("ready"); } }
When using Spring, we have to provide the configuration.
First I define my Job-bean
<bean id="myBean"> <property name="message" value="TEST" /> </bean>
After that I configure Quartz:
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" scope="singleton"> <property name="triggers"> <list> <!-- trigger list --> <ref bean="job1" /> </list> </property> </bean>
The binding between job and Quartz is done via a configured CronTriggerBean.
<bean id="job1"> <property name="cronExpression" value="0/2 * * * * ?" /> <property name="jobDetail"> <bean> <property name="name" value="job1" /> <property name="group" value="nightlyJobs" /> <!-- Delegieren auf unsere Bean und unsere Methode --> <property name="targetObject" ref="myBean" /> <property name="targetMethod" value="doIt" /> <property name="concurrent" value="false" /> </bean> </property> </bean>
This CronTriggerBean defines two values:
1. cronExpression specifies when to run the job. An explanation about that syntax can be found at http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger.
2. jobDetail specifies a JavaBean with information about the job. But we dont have to write this Bean, we just can configure the generic one from Spring:
- name and group for controlling the execution via control interfaces
- targetObject and targetMethod for the delegation to our JobBean
- specify if this job should run in concurrent mode (where concurrent means in one VM!)
Building this sample with Maven is easy. You’ll need just following dependencies:
- org.springframework::spring-core::3.0.5.RELEASE
- org.springframework::spring-context::3.0.5.RELEASE
- org.springframework::spring-context-support::3.0.5.RELEASE
- org.springframework::spring-tx::3.0.5.RELEASE
- org.quartz-scheduler::quartz::1.8.5
- junit::junit::4.9::{scope=test}
As far as I read you can’t use Quartz 2.x because Spring 3 doesnt support that. But I havent tried it.
When running you’ll get this output:
Starting Spring and within that: Quartz ... logs from Spring ... infos from SLF4J INFO: Starting Quartz Scheduler now Wait for job output Hello World: TEST Hello World: TEST Hello World: TEST Hello World: TEST Hello World: TEST ready
