From 91297d98636fee4c4e84fc720e6073e70127c62e Mon Sep 17 00:00:00 2001 From: Mark Fisher Date: Thu, 5 Nov 2009 23:41:01 +0000 Subject: [PATCH] SPR-6307 Quartz SchedulerFactoryBean now "auto-starts" upon receiving a ContextRefreshedEvent rather than within afterPropertiesSet(). --- .../quartz/SchedulerFactoryBean.java | 29 ++++++++++--- .../scheduling/quartz/QuartzSupportTests.java | 43 ++++++++++++++++++- 2 files changed, 64 insertions(+), 8 deletions(-) diff --git a/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java b/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java index c5b97d0f195..9be3e20fdcc 100644 --- a/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java +++ b/org.springframework.context.support/src/main/java/org/springframework/scheduling/quartz/SchedulerFactoryBean.java @@ -32,13 +32,17 @@ import org.quartz.simpl.SimpleThreadPool; import org.quartz.spi.JobFactory; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; import org.springframework.context.Lifecycle; +import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.PropertiesLoaderUtils; @@ -87,7 +91,8 @@ import org.springframework.util.CollectionUtils; * @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean */ public class SchedulerFactoryBean extends SchedulerAccessor - implements FactoryBean, BeanNameAware, ApplicationContextAware, InitializingBean, DisposableBean, Lifecycle { + implements FactoryBean, BeanNameAware, ApplicationContextAware, + ApplicationListener, InitializingBean, DisposableBean, Lifecycle { public static final String PROP_THREAD_COUNT = "org.quartz.threadPool.threadCount"; @@ -481,11 +486,6 @@ public class SchedulerFactoryBean extends SchedulerAccessor registerListeners(); 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 //--------------------------------------------------------------------- diff --git a/org.springframework.context.support/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java b/org.springframework.context.support/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java index 970687efa04..e1bd9a8c639 100644 --- a/org.springframework.context.support/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java +++ b/org.springframework.context.support/src/test/java/org/springframework/scheduling/quartz/QuartzSupportTests.java @@ -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"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.scheduling.quartz; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; @@ -29,7 +30,6 @@ import java.util.Map; import javax.sql.DataSource; -import junit.framework.TestCase; import org.easymock.MockControl; import org.junit.Test; import org.quartz.CronTrigger; @@ -51,6 +51,9 @@ import org.quartz.impl.SchedulerRepository; import org.quartz.spi.JobFactory; 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.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.StaticApplicationContext; @@ -64,6 +67,7 @@ import org.springframework.scheduling.TestMethodInvokingTask; * @author Alef Arendsen * @author Rob Harrop * @author Dave Syer + * @author Mark Fisher * @since 20.02.2004 */ public class QuartzSupportTests { @@ -164,6 +168,7 @@ public class QuartzSupportTests { schedulerFactoryBean.setTriggers(new Trigger[] {trigger0, trigger1}); try { schedulerFactoryBean.afterPropertiesSet(); + schedulerFactoryBean.start(); } finally { schedulerFactoryBean.destroy(); @@ -257,6 +262,7 @@ public class QuartzSupportTests { } try { schedulerFactoryBean.afterPropertiesSet(); + schedulerFactoryBean.start(); } finally { schedulerFactoryBean.destroy(); @@ -354,6 +360,7 @@ public class QuartzSupportTests { } try { schedulerFactoryBean.afterPropertiesSet(); + schedulerFactoryBean.start(); } finally { schedulerFactoryBean.destroy(); @@ -406,6 +413,7 @@ public class QuartzSupportTests { schedulerFactoryBean.setTriggerListeners(new TriggerListener[] {triggerListener}); try { schedulerFactoryBean.afterPropertiesSet(); + schedulerFactoryBean.start(); } finally { schedulerFactoryBean.destroy(); @@ -571,6 +579,7 @@ public class QuartzSupportTests { schedulerFactoryBean.setTriggers(new Trigger[] {trigger0, trigger1}); try { schedulerFactoryBean.afterPropertiesSet(); + schedulerFactoryBean.start(); } finally { schedulerFactoryBean.destroy(); @@ -608,6 +617,7 @@ public class QuartzSupportTests { schedulerFactoryBean.setApplicationContextSchedulerContextKey("appCtx"); try { schedulerFactoryBean.afterPropertiesSet(); + schedulerFactoryBean.start(); Scheduler returnedScheduler = (Scheduler) schedulerFactoryBean.getObject(); assertEquals(tb, returnedScheduler.getContext().get("testBean")); assertEquals(ac, returnedScheduler.getContext().get("appCtx")); @@ -703,6 +713,7 @@ public class QuartzSupportTests { bean.setTriggers(new Trigger[] {trigger}); bean.setJobDetails(new JobDetail[] {jobDetail}); bean.afterPropertiesSet(); + bean.start(); Thread.sleep(500); assertTrue(DummyJob.count > 0); @@ -731,6 +742,7 @@ public class QuartzSupportTests { bean.setTriggers(new Trigger[] {trigger}); bean.setJobDetails(new JobDetail[] {jobDetail}); bean.afterPropertiesSet(); + bean.start(); Thread.sleep(500); assertTrue(DummyRunnable.count > 0); @@ -760,6 +772,7 @@ public class QuartzSupportTests { bean.setTriggers(new Trigger[] {trigger}); bean.setJobDetails(new JobDetail[] {jobDetail}); bean.afterPropertiesSet(); + bean.start(); Thread.sleep(500); assertEquals(10, DummyJobBean.param); @@ -792,6 +805,7 @@ public class QuartzSupportTests { bean.setTriggers(new Trigger[] {trigger}); bean.setJobDetails(new JobDetail[] {jobDetail}); bean.afterPropertiesSet(); + bean.start(); Thread.sleep(500); assertEquals(10, DummyJob.param); @@ -857,6 +871,7 @@ public class QuartzSupportTests { bean.setTriggers(new Trigger[] {trigger}); bean.setJobDetails(new JobDetail[] {jobDetail}); bean.afterPropertiesSet(); + bean.start(); Thread.sleep(500); assertEquals(10, DummyRunnable.param); @@ -888,6 +903,7 @@ public class QuartzSupportTests { bean.setTriggers(new Trigger[] {trigger}); bean.setJobDetails(new JobDetail[] {jobDetail}); bean.afterPropertiesSet(); + bean.start(); Thread.sleep(500); assertEquals(10, DummyJobBean.param); @@ -906,6 +922,7 @@ public class QuartzSupportTests { bean.setJobSchedulingDataLocation("org/springframework/scheduling/quartz/job-scheduling-data.xml"); bean.setResourceLoader(new FileSystemResourceLoader()); bean.afterPropertiesSet(); + bean.start(); Thread.sleep(500); 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 public void testSchedulerRepositoryExposure() throws InterruptedException { ClassPathXmlApplicationContext ctx =