SPR-6307 Quartz SchedulerFactoryBean now "auto-starts" upon receiving a ContextRefreshedEvent rather than within afterPropertiesSet().

This commit is contained in:
Mark Fisher 2009-11-05 23:41:01 +00:00
parent 40720ab0f1
commit 91297d9863
2 changed files with 64 additions and 8 deletions

View File

@ -32,13 +32,17 @@ import org.quartz.simpl.SimpleThreadPool;
import org.quartz.spi.JobFactory; import org.quartz.spi.JobFactory;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.Lifecycle; import org.springframework.context.Lifecycle;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.core.io.support.PropertiesLoaderUtils;
@ -87,7 +91,8 @@ import org.springframework.util.CollectionUtils;
* @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean * @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean
*/ */
public class SchedulerFactoryBean extends SchedulerAccessor public class SchedulerFactoryBean extends SchedulerAccessor
implements FactoryBean<Scheduler>, BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean, Lifecycle { implements FactoryBean<Scheduler>, BeanNameAware, ApplicationContextAware,
ApplicationListener<ApplicationEvent>, InitializingBean, DisposableBean, Lifecycle {
public static final String PROP_THREAD_COUNT = "org.quartz.threadPool.threadCount"; public static final String PROP_THREAD_COUNT = "org.quartz.threadPool.threadCount";
@ -481,11 +486,6 @@ public class SchedulerFactoryBean extends SchedulerAccessor
registerListeners(); registerListeners();
registerJobsAndTriggers(); registerJobsAndTriggers();
// Start Scheduler immediately, if demanded.
if (this.autoStartup) {
startScheduler(this.scheduler, this.startupDelay);
}
} }
@ -678,6 +678,23 @@ public class SchedulerFactoryBean extends SchedulerAccessor
} }
//---------------------------------------------------------------------
// Implementation of ApplicationListener interface
//---------------------------------------------------------------------
public void onApplicationEvent(ApplicationEvent event) {
// auto-start Scheduler if demanded
if (event instanceof ContextRefreshedEvent && this.autoStartup) {
try {
startScheduler(this.scheduler, this.startupDelay);
}
catch (SchedulerException e) {
throw new BeanInitializationException("failed to auto-start scheduler", e);
}
}
}
//--------------------------------------------------------------------- //---------------------------------------------------------------------
// Implementation of Lifecycle interface // Implementation of Lifecycle interface
//--------------------------------------------------------------------- //---------------------------------------------------------------------

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2008 the original author or authors. * Copyright 2002-2009 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
package org.springframework.scheduling.quartz; package org.springframework.scheduling.quartz;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -29,7 +30,6 @@ import java.util.Map;
import javax.sql.DataSource; import javax.sql.DataSource;
import junit.framework.TestCase;
import org.easymock.MockControl; import org.easymock.MockControl;
import org.junit.Test; import org.junit.Test;
import org.quartz.CronTrigger; import org.quartz.CronTrigger;
@ -51,6 +51,9 @@ import org.quartz.impl.SchedulerRepository;
import org.quartz.spi.JobFactory; import org.quartz.spi.JobFactory;
import org.springframework.beans.TestBean; import org.springframework.beans.TestBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.support.StaticListableBeanFactory; import org.springframework.beans.factory.support.StaticListableBeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.StaticApplicationContext; import org.springframework.context.support.StaticApplicationContext;
@ -64,6 +67,7 @@ import org.springframework.scheduling.TestMethodInvokingTask;
* @author Alef Arendsen * @author Alef Arendsen
* @author Rob Harrop * @author Rob Harrop
* @author Dave Syer * @author Dave Syer
* @author Mark Fisher
* @since 20.02.2004 * @since 20.02.2004
*/ */
public class QuartzSupportTests { public class QuartzSupportTests {
@ -164,6 +168,7 @@ public class QuartzSupportTests {
schedulerFactoryBean.setTriggers(new Trigger[] {trigger0, trigger1}); schedulerFactoryBean.setTriggers(new Trigger[] {trigger0, trigger1});
try { try {
schedulerFactoryBean.afterPropertiesSet(); schedulerFactoryBean.afterPropertiesSet();
schedulerFactoryBean.start();
} }
finally { finally {
schedulerFactoryBean.destroy(); schedulerFactoryBean.destroy();
@ -257,6 +262,7 @@ public class QuartzSupportTests {
} }
try { try {
schedulerFactoryBean.afterPropertiesSet(); schedulerFactoryBean.afterPropertiesSet();
schedulerFactoryBean.start();
} }
finally { finally {
schedulerFactoryBean.destroy(); schedulerFactoryBean.destroy();
@ -354,6 +360,7 @@ public class QuartzSupportTests {
} }
try { try {
schedulerFactoryBean.afterPropertiesSet(); schedulerFactoryBean.afterPropertiesSet();
schedulerFactoryBean.start();
} }
finally { finally {
schedulerFactoryBean.destroy(); schedulerFactoryBean.destroy();
@ -406,6 +413,7 @@ public class QuartzSupportTests {
schedulerFactoryBean.setTriggerListeners(new TriggerListener[] {triggerListener}); schedulerFactoryBean.setTriggerListeners(new TriggerListener[] {triggerListener});
try { try {
schedulerFactoryBean.afterPropertiesSet(); schedulerFactoryBean.afterPropertiesSet();
schedulerFactoryBean.start();
} }
finally { finally {
schedulerFactoryBean.destroy(); schedulerFactoryBean.destroy();
@ -571,6 +579,7 @@ public class QuartzSupportTests {
schedulerFactoryBean.setTriggers(new Trigger[] {trigger0, trigger1}); schedulerFactoryBean.setTriggers(new Trigger[] {trigger0, trigger1});
try { try {
schedulerFactoryBean.afterPropertiesSet(); schedulerFactoryBean.afterPropertiesSet();
schedulerFactoryBean.start();
} }
finally { finally {
schedulerFactoryBean.destroy(); schedulerFactoryBean.destroy();
@ -608,6 +617,7 @@ public class QuartzSupportTests {
schedulerFactoryBean.setApplicationContextSchedulerContextKey("appCtx"); schedulerFactoryBean.setApplicationContextSchedulerContextKey("appCtx");
try { try {
schedulerFactoryBean.afterPropertiesSet(); schedulerFactoryBean.afterPropertiesSet();
schedulerFactoryBean.start();
Scheduler returnedScheduler = (Scheduler) schedulerFactoryBean.getObject(); Scheduler returnedScheduler = (Scheduler) schedulerFactoryBean.getObject();
assertEquals(tb, returnedScheduler.getContext().get("testBean")); assertEquals(tb, returnedScheduler.getContext().get("testBean"));
assertEquals(ac, returnedScheduler.getContext().get("appCtx")); assertEquals(ac, returnedScheduler.getContext().get("appCtx"));
@ -703,6 +713,7 @@ public class QuartzSupportTests {
bean.setTriggers(new Trigger[] {trigger}); bean.setTriggers(new Trigger[] {trigger});
bean.setJobDetails(new JobDetail[] {jobDetail}); bean.setJobDetails(new JobDetail[] {jobDetail});
bean.afterPropertiesSet(); bean.afterPropertiesSet();
bean.start();
Thread.sleep(500); Thread.sleep(500);
assertTrue(DummyJob.count > 0); assertTrue(DummyJob.count > 0);
@ -731,6 +742,7 @@ public class QuartzSupportTests {
bean.setTriggers(new Trigger[] {trigger}); bean.setTriggers(new Trigger[] {trigger});
bean.setJobDetails(new JobDetail[] {jobDetail}); bean.setJobDetails(new JobDetail[] {jobDetail});
bean.afterPropertiesSet(); bean.afterPropertiesSet();
bean.start();
Thread.sleep(500); Thread.sleep(500);
assertTrue(DummyRunnable.count > 0); assertTrue(DummyRunnable.count > 0);
@ -760,6 +772,7 @@ public class QuartzSupportTests {
bean.setTriggers(new Trigger[] {trigger}); bean.setTriggers(new Trigger[] {trigger});
bean.setJobDetails(new JobDetail[] {jobDetail}); bean.setJobDetails(new JobDetail[] {jobDetail});
bean.afterPropertiesSet(); bean.afterPropertiesSet();
bean.start();
Thread.sleep(500); Thread.sleep(500);
assertEquals(10, DummyJobBean.param); assertEquals(10, DummyJobBean.param);
@ -792,6 +805,7 @@ public class QuartzSupportTests {
bean.setTriggers(new Trigger[] {trigger}); bean.setTriggers(new Trigger[] {trigger});
bean.setJobDetails(new JobDetail[] {jobDetail}); bean.setJobDetails(new JobDetail[] {jobDetail});
bean.afterPropertiesSet(); bean.afterPropertiesSet();
bean.start();
Thread.sleep(500); Thread.sleep(500);
assertEquals(10, DummyJob.param); assertEquals(10, DummyJob.param);
@ -857,6 +871,7 @@ public class QuartzSupportTests {
bean.setTriggers(new Trigger[] {trigger}); bean.setTriggers(new Trigger[] {trigger});
bean.setJobDetails(new JobDetail[] {jobDetail}); bean.setJobDetails(new JobDetail[] {jobDetail});
bean.afterPropertiesSet(); bean.afterPropertiesSet();
bean.start();
Thread.sleep(500); Thread.sleep(500);
assertEquals(10, DummyRunnable.param); assertEquals(10, DummyRunnable.param);
@ -888,6 +903,7 @@ public class QuartzSupportTests {
bean.setTriggers(new Trigger[] {trigger}); bean.setTriggers(new Trigger[] {trigger});
bean.setJobDetails(new JobDetail[] {jobDetail}); bean.setJobDetails(new JobDetail[] {jobDetail});
bean.afterPropertiesSet(); bean.afterPropertiesSet();
bean.start();
Thread.sleep(500); Thread.sleep(500);
assertEquals(10, DummyJobBean.param); assertEquals(10, DummyJobBean.param);
@ -906,6 +922,7 @@ public class QuartzSupportTests {
bean.setJobSchedulingDataLocation("org/springframework/scheduling/quartz/job-scheduling-data.xml"); bean.setJobSchedulingDataLocation("org/springframework/scheduling/quartz/job-scheduling-data.xml");
bean.setResourceLoader(new FileSystemResourceLoader()); bean.setResourceLoader(new FileSystemResourceLoader());
bean.afterPropertiesSet(); bean.afterPropertiesSet();
bean.start();
Thread.sleep(500); Thread.sleep(500);
assertEquals(10, DummyJob.param); assertEquals(10, DummyJob.param);
@ -971,6 +988,28 @@ public class QuartzSupportTests {
} }
} }
@Test
public void testSchedulerAutoStartsOnContextRefreshedEventByDefault() throws Exception {
StaticApplicationContext context = new StaticApplicationContext();
context.registerBeanDefinition("scheduler", new RootBeanDefinition(SchedulerFactoryBean.class));
Scheduler bean = context.getBean("scheduler", Scheduler.class);
assertFalse(bean.isStarted());
context.refresh();
assertTrue(bean.isStarted());
}
@Test
public void testSchedulerAutoStartupFalse() throws Exception {
StaticApplicationContext context = new StaticApplicationContext();
BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(
SchedulerFactoryBean.class).addPropertyValue("autoStartup", false).getBeanDefinition();
context.registerBeanDefinition("scheduler", beanDefinition);
Scheduler bean = context.getBean("scheduler", Scheduler.class);
assertFalse(bean.isStarted());
context.refresh();
assertFalse(bean.isStarted());
}
@Test @Test
public void testSchedulerRepositoryExposure() throws InterruptedException { public void testSchedulerRepositoryExposure() throws InterruptedException {
ClassPathXmlApplicationContext ctx = ClassPathXmlApplicationContext ctx =