diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java
index ccda008fcc8..19896362fb7 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/Scheduled.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -24,11 +24,11 @@ import java.lang.annotation.Target;
/**
* Annotation that marks a method to be scheduled. Exactly one of the
- * cron, fixedDelay, or fixedRate
- * attributes must be provided.
+ * {@link #cron()}, {@link #fixedDelay()}, or {@link #fixedRate()}
+ * attributes must be specified.
*
*
The annotated method must expect no arguments and have a
- * void return type.
+ * {@code void} return type.
*
*
Processing of {@code @Scheduled} annotations is performed by
* registering a {@link ScheduledAnnotationBeanPostProcessor}. This can be
@@ -49,9 +49,10 @@ public @interface Scheduled {
/**
* A cron-like expression, extending the usual UN*X definition to include
* triggers on the second as well as minute, hour, day of month, month
- * and day of week. e.g. "0 * * * * MON-FRI" means once
- * per minute on weekdays (at the top of the minute - the 0th second).
+ * and day of week. e.g. {@code "0 * * * * MON-FRI"} means once per minute on
+ * weekdays (at the top of the minute - the 0th second).
* @return an expression that can be parsed to a cron schedule
+ * @see org.springframework.scheduling.support.CronSequenceGenerator
*/
String cron() default "";
diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
index 692270044ce..5343d13ced3 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.annotation;
import java.lang.reflect.Method;
+
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
@@ -104,7 +105,6 @@ public class ScheduledAnnotationBeanPostProcessor
return LOWEST_PRECEDENCE;
}
-
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
@@ -124,9 +124,11 @@ public class ScheduledAnnotationBeanPostProcessor
// found a @Scheduled method on the target class for this JDK proxy -> is it
// also present on the proxy itself?
method = bean.getClass().getMethod(method.getName(), method.getParameterTypes());
- } catch (SecurityException ex) {
+ }
+ catch (SecurityException ex) {
ReflectionUtils.handleReflectionException(ex);
- } catch (NoSuchMethodException ex) {
+ }
+ catch (NoSuchMethodException ex) {
throw new IllegalStateException(String.format(
"@Scheduled method '%s' found on bean target class '%s', " +
"but not found in any interface(s) for bean JDK proxy. Either " +
@@ -137,7 +139,7 @@ public class ScheduledAnnotationBeanPostProcessor
}
Runnable runnable = new ScheduledMethodRunnable(bean, method);
boolean processedSchedule = false;
- String errorMessage = "Exactly one of 'cron', 'fixedDelay', or 'fixedRate' is required.";
+ String errorMessage = "Exactly one of the 'cron', 'fixedDelay', or 'fixedRate' attributes is required.";
String cron = annotation.cron();
if (!"".equals(cron)) {
processedSchedule = true;
@@ -170,7 +172,8 @@ public class ScheduledAnnotationBeanPostProcessor
return;
}
- Map configurers = applicationContext.getBeansOfType(SchedulingConfigurer.class);
+ Map configurers =
+ this.applicationContext.getBeansOfType(SchedulingConfigurer.class);
if (this.cronTasks.isEmpty() && this.fixedDelayTasks.isEmpty() &&
this.fixedRateTasks.isEmpty() && configurers.isEmpty()) {
@@ -190,19 +193,23 @@ public class ScheduledAnnotationBeanPostProcessor
configurer.configureTasks(this.registrar);
}
- if (registrar.getScheduler() == null) {
+ if (this.registrar.getScheduler() == null) {
Map schedulers = new HashMap();
schedulers.putAll(applicationContext.getBeansOfType(TaskScheduler.class));
schedulers.putAll(applicationContext.getBeansOfType(ScheduledExecutorService.class));
if (schedulers.size() == 0) {
// do nothing -> fall back to default scheduler
- } else if (schedulers.size() == 1) {
+ }
+ else if (schedulers.size() == 1) {
this.registrar.setScheduler(schedulers.values().iterator().next());
- } else if (schedulers.size() >= 2){
- throw new IllegalStateException("More than one TaskScheduler and/or ScheduledExecutorService " +
- "exist within the context. Remove all but one of the beans; or implement the " +
- "SchedulingConfigurer interface and call ScheduledTaskRegistrar#setScheduler " +
- "explicitly within the configureTasks() callback. Found the following beans: " + schedulers.keySet());
+ }
+ else if (schedulers.size() >= 2){
+ throw new IllegalStateException(
+ "More than one TaskScheduler and/or ScheduledExecutorService " +
+ "exist within the context. Remove all but one of the beans; or " +
+ "implement the SchedulingConfigurer interface and call " +
+ "ScheduledTaskRegistrar#setScheduler explicitly within the " +
+ "configureTasks() callback. Found the following beans: " + schedulers.keySet());
}
}
diff --git a/spring-context/src/main/java/org/springframework/scheduling/annotation/SchedulingConfigurer.java b/spring-context/src/main/java/org/springframework/scheduling/annotation/SchedulingConfigurer.java
index d4787c0e4cc..761f151f384 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/annotation/SchedulingConfigurer.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/annotation/SchedulingConfigurer.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -19,12 +19,15 @@ package org.springframework.scheduling.annotation;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
/**
- * Interface to be implemented by @{@link org.springframework.context.annotation.Configuration}
- * classes annotated with @{@link EnableScheduling} that wish to register scheduled tasks
- * in a programmatic fashion as opposed to the declarative approach of
- * using the @{@link Scheduled} annotation. For example, this may be necessary when
- * implementing {@link org.springframework.scheduling.Trigger Trigger}-based tasks, which
- * are not supported by the {@code @Scheduled} annotation.
+ * Optional interface to be implemented by @{@link
+ * org.springframework.context.annotation.Configuration Configuration} classes annotated
+ * with @{@link EnableScheduling}. Typically used for setting a specific
+ * {@link org.springframework.scheduling.TaskScheduler TaskScheduler} bean to be used when
+ * executing scheduled tasks or for registering scheduled tasks in a programmatic
+ * fashion as opposed to the declarative approach of using the @{@link Scheduled}
+ * annotation. For example, this may be necessary when implementing {@link
+ * org.springframework.scheduling.Trigger Trigger}-based tasks, which are not supported by
+ * the {@code @Scheduled} annotation.
*
* See @{@link EnableScheduling} for detailed usage examples.
*
diff --git a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java b/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java
index 1898441e217..a3708a5b85b 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTaskRegistrar.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -65,7 +65,7 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
/**
- * Set the TaskScheduler to register scheduled tasks with.
+ * Set the {@link TaskScheduler} to register scheduled tasks with.
*/
public void setTaskScheduler(TaskScheduler taskScheduler) {
Assert.notNull(taskScheduler, "TaskScheduler must not be null");
@@ -73,9 +73,9 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
}
/**
- * Set the {@link org.springframework.scheduling.TaskScheduler} to register scheduled
- * tasks with, or a {@link java.util.concurrent.ScheduledExecutorService} to be
- * wrapped as a TaskScheduler.
+ * Set the {@link TaskScheduler} to register scheduled tasks with, or a
+ * {@link java.util.concurrent.ScheduledExecutorService} to be wrapped as a
+ * {@code TaskScheduler}.
*/
public void setScheduler(Object scheduler) {
Assert.notNull(scheduler, "Scheduler object must not be null");
@@ -91,7 +91,7 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
}
/**
- * Return the scheduler instance for this registrar (may be null)
+ * Return the {@link TaskScheduler} instance for this registrar (may be {@code null}).
*/
public TaskScheduler getScheduler() {
return this.taskScheduler;
@@ -121,6 +121,14 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
this.fixedRateTasks = fixedRateTasks;
}
+ /**
+ * Specify triggered tasks as a Map of Runnables (the tasks) and fixed-delay values.
+ * @see TaskScheduler#scheduleWithFixedDelay(Runnable, long)
+ */
+ public void setFixedDelayTasks(Map fixedDelayTasks) {
+ this.fixedDelayTasks = fixedDelayTasks;
+ }
+
/**
* Add a Runnable task to be triggered per the given {@link Trigger}.
* @see TaskScheduler#scheduleAtFixedRate(Runnable, long)
@@ -142,17 +150,6 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
this.cronTasks.put(task, cronExpression);
}
- /**
- * Add a Runnable task to be triggered with the given fixed delay.
- * @see TaskScheduler#scheduleWithFixedDelay(Runnable, long)
- */
- public void addFixedDelayTask(Runnable task, long delay) {
- if (this.fixedDelayTasks == null) {
- this.fixedDelayTasks = new HashMap();
- }
- this.fixedDelayTasks.put(task, delay);
- }
-
/**
* Add a Runnable task to be triggered at the given fixed-rate period.
* @see TaskScheduler#scheduleAtFixedRate(Runnable, long)
@@ -165,14 +162,20 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
}
/**
- * Specify triggered tasks as a Map of Runnables (the tasks) and fixed-delay values.
+ * Add a Runnable task to be triggered with the given fixed delay.
* @see TaskScheduler#scheduleWithFixedDelay(Runnable, long)
*/
- public void setFixedDelayTasks(Map fixedDelayTasks) {
- this.fixedDelayTasks = fixedDelayTasks;
+ public void addFixedDelayTask(Runnable task, long delay) {
+ if (this.fixedDelayTasks == null) {
+ this.fixedDelayTasks = new HashMap();
+ }
+ this.fixedDelayTasks.put(task, delay);
}
-
+ /**
+ * Schedule all registered tasks against the underlying {@linkplain
+ * #setTaskScheduler(TaskScheduler) task scheduler.
+ */
public void afterPropertiesSet() {
if (this.taskScheduler == null) {
this.localExecutor = Executors.newSingleThreadScheduledExecutor();
@@ -200,7 +203,6 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
}
}
-
public void destroy() {
for (ScheduledFuture> future : this.scheduledFutures) {
future.cancel(true);
diff --git a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTasksBeanDefinitionParser.java b/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTasksBeanDefinitionParser.java
index 6e29ad4f102..52093b354e3 100644
--- a/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTasksBeanDefinitionParser.java
+++ b/spring-context/src/main/java/org/springframework/scheduling/config/ScheduledTasksBeanDefinitionParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -16,10 +16,6 @@
package org.springframework.scheduling.config;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
@@ -28,6 +24,10 @@ import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
/**
* Parser for the 'scheduled-tasks' element of the scheduling namespace.
*
@@ -87,9 +87,8 @@ public class ScheduledTasksBeanDefinitionParser extends AbstractSingleBeanDefini
if (!(hasCronAttribute | hasFixedDelayAttribute | hasFixedRateAttribute | hasTriggerAttribute)) {
parserContext.getReaderContext().error(
- "exactly one of the 'cron', 'fixed-delay', 'fixed-rate', or 'trigger' attributes is required", taskElement);
- // Continue with the possible next task element
- continue;
+ "one of the 'cron', 'fixed-delay', 'fixed-rate', or 'trigger' attributes is required", taskElement);
+ continue; // with the possible next task element
}
if (hasCronAttribute) {
diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java
index 9b98b48929b..1d7abd9b2bd 100644
--- a/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java
+++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/EnableSchedulingTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -16,15 +16,11 @@
package org.springframework.scheduling.annotation;
-import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.greaterThanOrEqualTo;
-import static org.hamcrest.Matchers.startsWith;
-import static org.junit.Assert.assertThat;
-
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Test;
+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -34,6 +30,10 @@ import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
+import static org.hamcrest.Matchers.*;
+
+import static org.junit.Assert.*;
+
/**
* Tests use of @EnableScheduling on @Configuration classes.
*
diff --git a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java
index f1ffde04117..81ca20bdea2 100644
--- a/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java
+++ b/spring-context/src/test/java/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessorTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -25,7 +25,6 @@ import java.lang.reflect.Method;
import java.util.Map;
import java.util.Properties;
-import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
@@ -37,6 +36,8 @@ import org.springframework.context.support.StaticApplicationContext;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
+import static org.junit.Assert.*;
+
/**
* @author Mark Fisher
* @author Juergen Hoeller
@@ -269,7 +270,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
- public static class FixedDelayTestBean {
+ static class FixedDelayTestBean {
@Scheduled(fixedDelay=5000)
public void fixedDelay() {
@@ -277,7 +278,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
- public static class FixedRateTestBean {
+ static class FixedRateTestBean {
@Scheduled(fixedRate=3000)
public void fixedRate() {
@@ -285,7 +286,15 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
- public static class CronTestBean {
+ static class FixedRateWithInitialDelayTestBean {
+
+ @Scheduled(initialDelay=1000, fixedRate=3000)
+ public void fixedRate() {
+ }
+ }
+
+
+ static class CronTestBean {
@Scheduled(cron="*/7 * * * * ?")
public void cron() throws IOException {
@@ -295,7 +304,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
- private static class EmptyAnnotationTestBean {
+ static class EmptyAnnotationTestBean {
@Scheduled
public void invalid() {
@@ -304,7 +313,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
- private static class InvalidCronTestBean {
+ static class InvalidCronTestBean {
@Scheduled(cron="abc")
public void invalid() {
@@ -313,7 +322,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
- private static class NonVoidReturnTypeTestBean {
+ static class NonVoidReturnTypeTestBean {
@Scheduled(fixedRate=3000)
public String invalid() {
@@ -323,7 +332,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
- private static class NonEmptyParamListTestBean {
+ static class NonEmptyParamListTestBean {
@Scheduled(fixedRate=3000)
public void invalid(String oops) {
@@ -344,7 +353,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
private static @interface Hourly {}
- private static class MetaAnnotationFixedRateTestBean {
+ static class MetaAnnotationFixedRateTestBean {
@EveryFiveSeconds
public void checkForUpdates() {
@@ -352,7 +361,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
- private static class MetaAnnotationCronTestBean {
+ static class MetaAnnotationCronTestBean {
@Hourly
public void generateReport() {
@@ -360,7 +369,7 @@ public class ScheduledAnnotationBeanPostProcessorTests {
}
- private static class PropertyPlaceholderTestBean {
+ static class PropertyPlaceholderTestBean {
@Scheduled(cron = "${schedules.businessHours}")
public void x() {
@@ -370,11 +379,11 @@ public class ScheduledAnnotationBeanPostProcessorTests {
@Scheduled(cron = "${schedules.businessHours}")
@Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
+ @Retention(RetentionPolicy.RUNTIME)
private static @interface BusinessHours {}
- private static class PropertyPlaceholderMetaAnnotationTestBean {
+ static class PropertyPlaceholderMetaAnnotationTestBean {
@BusinessHours
public void y() {
diff --git a/spring-context/src/test/java/org/springframework/scheduling/config/ScheduledTasksBeanDefinitionParserTests.java b/spring-context/src/test/java/org/springframework/scheduling/config/ScheduledTasksBeanDefinitionParserTests.java
index f24355093f9..776b5108f5a 100644
--- a/spring-context/src/test/java/org/springframework/scheduling/config/ScheduledTasksBeanDefinitionParserTests.java
+++ b/spring-context/src/test/java/org/springframework/scheduling/config/ScheduledTasksBeanDefinitionParserTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2011 the original author or authors.
+ * Copyright 2002-2012 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.
@@ -21,7 +21,6 @@ import java.util.Collection;
import java.util.Date;
import java.util.Map;
-import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
@@ -32,6 +31,8 @@ import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
+import static org.junit.Assert.*;
+
/**
* @author Mark Fisher
*/
diff --git a/src/reference/docbook/scheduling.xml b/src/reference/docbook/scheduling.xml
index 75b31ba03e6..93ea81dfa30 100644
--- a/src/reference/docbook/scheduling.xml
+++ b/src/reference/docbook/scheduling.xml
@@ -472,7 +472,7 @@ public class TaskExecutorExample {
example.
<task:scheduled-tasks scheduler="myScheduler">
- <task:scheduled ref="someObject" method="someMethod" fixed-delay="5000"/>
+ <task:scheduled ref="beanA" method="methodA" fixed-delay="5000"/>
</task:scheduled-tasks>
<task:scheduler id="myScheduler" pool-size="10"/>
@@ -480,13 +480,16 @@ public class TaskExecutorExample {
As you can see, the scheduler is referenced by the outer element,
and each individual task includes the configuration of its trigger
metadata. In the preceding example, that metadata defines a periodic
- trigger with a fixed delay. It could also be configured with a
- "fixed-rate", or for more control, a "cron" attribute could be provided
- instead. Here's an example featuring these other options.
+ trigger with a fixed delay indicating the number of milliseconds to wait
+ after each task execution has completed. Another option is 'fixed-rate',
+ indicating how often the method should be executed regardless of how long
+ any previous execution takes. For more control, a "cron" attribute may be
+ provided instead. Here is an example demonstrating these other options.
+
<task:scheduled-tasks scheduler="myScheduler">
- <task:scheduled ref="someObject" method="someMethod" fixed-rate="5000"/>
- <task:scheduled ref="anotherObject" method="anotherMethod" cron="*/5 * * * * MON-FRI"/>
+ <task:scheduled ref="beanB" method="methodB" fixed-rate="5000"/>
+ <task:scheduled ref="beanC" method="methodC" cron="*/5 * * * * MON-FRI"/>
</task:scheduled-tasks>
<task:scheduler id="myScheduler" pool-size="10"/>