Support TimeUnit in the @Scheduled annotation

This commit introduces a new `timeUnit` attribute in the @Scheduled
annotation to allow the user to specify a time unit other than
milliseconds.

Closes gh-27309
This commit is contained in:
Axzial
2021-08-21 18:00:26 +02:00
committed by Sam Brannen
parent 3c2dfebf4e
commit e99b43b91e
3 changed files with 249 additions and 18 deletions

View File

@@ -22,6 +22,7 @@ import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
@@ -46,6 +47,7 @@ import org.springframework.scheduling.config.ScheduledTaskRegistrar;
* @author Juergen Hoeller
* @author Dave Syer
* @author Chris Beams
* @author Victor Brown
* @since 3.0
* @see EnableScheduling
* @see ScheduledAnnotationBeanPostProcessor
@@ -101,52 +103,64 @@ public @interface Scheduled {
String zone() default "";
/**
* Execute the annotated method with a fixed period in milliseconds between the
* Execute the annotated method with a fixed period between the
* end of the last invocation and the start of the next.
* @return the delay in milliseconds
* Using milliseconds by default with timeUnit().
* @return the delay
*/
long fixedDelay() default -1;
/**
* Execute the annotated method with a fixed period in milliseconds between the
* Execute the annotated method with a fixed period between the
* end of the last invocation and the start of the next.
* @return the delay in milliseconds as a String value, e.g. a placeholder
* Using milliseconds by default with fixedDelayTimeUnit().
* @return the delay as a String value, e.g. a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
*/
String fixedDelayString() default "";
/**
* Execute the annotated method with a fixed period in milliseconds between
* Execute the annotated method with a fixed period between
* invocations.
* @return the period in milliseconds
* Using milliseconds by default with timeUnit().
* @return the period
*/
long fixedRate() default -1;
/**
* Execute the annotated method with a fixed period in milliseconds between
* Execute the annotated method with a fixed period between
* invocations.
* @return the period in milliseconds as a String value, e.g. a placeholder
* Using milliseconds by default with fixedRateTimeUnit().
* @return the period as a String value, e.g. a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
*/
String fixedRateString() default "";
/**
* Number of milliseconds to delay before the first execution of a
* Number to delay before the first execution of a
* {@link #fixedRate} or {@link #fixedDelay} task.
* @return the initial delay in milliseconds
* Using milliseconds by default with timeUnit().
* @return the initial
* @since 3.2
*/
long initialDelay() default -1;
/**
* Number of milliseconds to delay before the first execution of a
* Number to delay before the first execution of a
* {@link #fixedRate} or {@link #fixedDelay} task.
* Using milliseconds by default with initialDelayTimeUnit().
* @return the initial delay in milliseconds as a String value, e.g. a placeholder
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
* @since 3.2.2
*/
String initialDelayString() default "";
/**
* Specify the {@link TimeUnit} to use for initialDelay, fixedRate and fixedDelay values.
* @return the {@link TimeUnit}, by default milliseconds will be used.
*/
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}

View File

@@ -30,6 +30,7 @@ import java.util.Set;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -94,6 +95,7 @@ import org.springframework.util.StringValueResolver;
* @author Juergen Hoeller
* @author Chris Beams
* @author Elizabeth Chatman
* @author Victor Brown
* @since 3.0
* @see Scheduled
* @see EnableScheduling
@@ -398,7 +400,7 @@ public class ScheduledAnnotationBeanPostProcessor
Set<ScheduledTask> tasks = new LinkedHashSet<>(4);
// Determine initial delay
long initialDelay = scheduled.initialDelay();
long initialDelay = TimeUnit.MILLISECONDS.convert(scheduled.initialDelay(), scheduled.timeUnit());
String initialDelayString = scheduled.initialDelayString();
if (StringUtils.hasText(initialDelayString)) {
Assert.isTrue(initialDelay < 0, "Specify 'initialDelay' or 'initialDelayString', not both");
@@ -407,7 +409,7 @@ public class ScheduledAnnotationBeanPostProcessor
}
if (StringUtils.hasLength(initialDelayString)) {
try {
initialDelay = parseDelayAsLong(initialDelayString);
initialDelay = TimeUnit.MILLISECONDS.convert(parseDelayAsLong(initialDelayString), scheduled.timeUnit());
}
catch (RuntimeException ex) {
throw new IllegalArgumentException(
@@ -446,12 +448,13 @@ public class ScheduledAnnotationBeanPostProcessor
}
// Check fixed delay
long fixedDelay = scheduled.fixedDelay();
long fixedDelay = TimeUnit.MILLISECONDS.convert(scheduled.fixedDelay(), scheduled.timeUnit());
if (fixedDelay >= 0) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay)));
}
String fixedDelayString = scheduled.fixedDelayString();
if (StringUtils.hasText(fixedDelayString)) {
if (this.embeddedValueResolver != null) {
@@ -461,7 +464,7 @@ public class ScheduledAnnotationBeanPostProcessor
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
try {
fixedDelay = parseDelayAsLong(fixedDelayString);
fixedDelay = TimeUnit.MILLISECONDS.convert(parseDelayAsLong(fixedDelayString), scheduled.timeUnit());
}
catch (RuntimeException ex) {
throw new IllegalArgumentException(
@@ -472,7 +475,7 @@ public class ScheduledAnnotationBeanPostProcessor
}
// Check fixed rate
long fixedRate = scheduled.fixedRate();
long fixedRate = TimeUnit.MILLISECONDS.convert(scheduled.fixedRate(), scheduled.timeUnit());
if (fixedRate >= 0) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
@@ -487,7 +490,7 @@ public class ScheduledAnnotationBeanPostProcessor
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
try {
fixedRate = parseDelayAsLong(fixedRateString);
fixedRate = TimeUnit.MILLISECONDS.convert(parseDelayAsLong(fixedRateString), scheduled.timeUnit());
}
catch (RuntimeException ex) {
throw new IllegalArgumentException(