Revise and document TimeUnit support in @Scheduled
This commit also fixes a bug introduced in commit e99b43b91e, where
java.time.Duration strings were converted to milliseconds and then
converted again using the configured TimeUnit.
See gh-27309
This commit is contained in:
@@ -48,6 +48,7 @@ import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||
* @author Dave Syer
|
||||
* @author Chris Beams
|
||||
* @author Victor Brown
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
* @see EnableScheduling
|
||||
* @see ScheduledAnnotationBeanPostProcessor
|
||||
@@ -103,63 +104,74 @@ public @interface Scheduled {
|
||||
String zone() default "";
|
||||
|
||||
/**
|
||||
* Execute the annotated method with a fixed period between the
|
||||
* end of the last invocation and the start of the next.
|
||||
* Using milliseconds by default with timeUnit().
|
||||
* Execute the annotated method with a fixed period between the end of the
|
||||
* last invocation and the start of the next.
|
||||
* <p>The time unit is milliseconds by default but can be overridden via
|
||||
* {@link #timeUnit}.
|
||||
* @return the delay
|
||||
*/
|
||||
long fixedDelay() default -1;
|
||||
|
||||
/**
|
||||
* Execute the annotated method with a fixed period between the
|
||||
* end of the last invocation and the start of the next.
|
||||
* Using milliseconds by default with fixedDelayTimeUnit().
|
||||
* @return the delay as a String value, e.g. a placeholder
|
||||
* Execute the annotated method with a fixed period between the end of the
|
||||
* last invocation and the start of the next.
|
||||
* <p>The time unit is milliseconds by default but can be overridden via
|
||||
* {@link #timeUnit}.
|
||||
* @return the delay as a String value — for example, 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 between
|
||||
* invocations.
|
||||
* Using milliseconds by default with timeUnit().
|
||||
* Execute the annotated method with a fixed period between invocations.
|
||||
* <p>The time unit is milliseconds by default but can be overridden via
|
||||
* {@link #timeUnit}.
|
||||
* @return the period
|
||||
*/
|
||||
long fixedRate() default -1;
|
||||
|
||||
/**
|
||||
* Execute the annotated method with a fixed period between
|
||||
* invocations.
|
||||
* Using milliseconds by default with fixedRateTimeUnit().
|
||||
* @return the period as a String value, e.g. a placeholder
|
||||
* Execute the annotated method with a fixed period between invocations.
|
||||
* <p>The time unit is milliseconds by default but can be overridden via
|
||||
* {@link #timeUnit}.
|
||||
* @return the period as a String value — for example, a placeholder
|
||||
* or a {@link java.time.Duration#parse java.time.Duration} compliant value
|
||||
* @since 3.2.2
|
||||
*/
|
||||
String fixedRateString() default "";
|
||||
|
||||
/**
|
||||
* Number to delay before the first execution of a
|
||||
* Number of units of time to delay before the first execution of a
|
||||
* {@link #fixedRate} or {@link #fixedDelay} task.
|
||||
* Using milliseconds by default with timeUnit().
|
||||
* <p>The time unit is milliseconds by default but can be overridden via
|
||||
* {@link #timeUnit}.
|
||||
* @return the initial
|
||||
* @since 3.2
|
||||
*/
|
||||
long initialDelay() default -1;
|
||||
|
||||
/**
|
||||
* Number to delay before the first execution of a
|
||||
* Number of units of time 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
|
||||
* <p>The time unit is milliseconds by default but can be overridden via
|
||||
* {@link #timeUnit}.
|
||||
* @return the initial delay as a String value — for example, 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.
|
||||
* The {@link TimeUnit} to use for {@link #fixedDelay}, {@link #fixedDelayString},
|
||||
* {@link #fixedRate}, {@link #fixedRateString}, {@link #initialDelay}, and
|
||||
* {@link #initialDelayString}.
|
||||
* <p>Defaults to {@link TimeUnit#MICROSECONDS}.
|
||||
* <p>This attribute is ignored for {@linkplain #cron() cron expressions}
|
||||
* and for {@link java.time.Duration} values supplied via {@link #fixedDelayString},
|
||||
* {@link #fixedRateString}, or {@link #initialDelayString}.
|
||||
* @return the {@code TimeUnit} to use
|
||||
* @since 5.3.10
|
||||
*/
|
||||
TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ import org.springframework.util.StringValueResolver;
|
||||
* @author Chris Beams
|
||||
* @author Elizabeth Chatman
|
||||
* @author Victor Brown
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
* @see Scheduled
|
||||
* @see EnableScheduling
|
||||
@@ -385,7 +386,7 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||
|
||||
/**
|
||||
* Process the given {@code @Scheduled} method declaration on the given bean.
|
||||
* @param scheduled the @Scheduled annotation
|
||||
* @param scheduled the {@code @Scheduled} annotation
|
||||
* @param method the method that the annotation has been declared on
|
||||
* @param bean the target bean instance
|
||||
* @see #createRunnable(Object, Method)
|
||||
@@ -400,7 +401,7 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||
Set<ScheduledTask> tasks = new LinkedHashSet<>(4);
|
||||
|
||||
// Determine initial delay
|
||||
long initialDelay = TimeUnit.MILLISECONDS.convert(scheduled.initialDelay(), scheduled.timeUnit());
|
||||
long initialDelay = convertToMillis(scheduled.initialDelay(), scheduled.timeUnit());
|
||||
String initialDelayString = scheduled.initialDelayString();
|
||||
if (StringUtils.hasText(initialDelayString)) {
|
||||
Assert.isTrue(initialDelay < 0, "Specify 'initialDelay' or 'initialDelayString', not both");
|
||||
@@ -409,7 +410,7 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||
}
|
||||
if (StringUtils.hasLength(initialDelayString)) {
|
||||
try {
|
||||
initialDelay = TimeUnit.MILLISECONDS.convert(parseDelayAsLong(initialDelayString), scheduled.timeUnit());
|
||||
initialDelay = convertToMillis(initialDelayString, scheduled.timeUnit());
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw new IllegalArgumentException(
|
||||
@@ -448,7 +449,7 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||
}
|
||||
|
||||
// Check fixed delay
|
||||
long fixedDelay = TimeUnit.MILLISECONDS.convert(scheduled.fixedDelay(), scheduled.timeUnit());
|
||||
long fixedDelay = convertToMillis(scheduled.fixedDelay(), scheduled.timeUnit());
|
||||
if (fixedDelay >= 0) {
|
||||
Assert.isTrue(!processedSchedule, errorMessage);
|
||||
processedSchedule = true;
|
||||
@@ -464,7 +465,7 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||
Assert.isTrue(!processedSchedule, errorMessage);
|
||||
processedSchedule = true;
|
||||
try {
|
||||
fixedDelay = TimeUnit.MILLISECONDS.convert(parseDelayAsLong(fixedDelayString), scheduled.timeUnit());
|
||||
fixedDelay = convertToMillis(fixedDelayString, scheduled.timeUnit());
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw new IllegalArgumentException(
|
||||
@@ -475,7 +476,7 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||
}
|
||||
|
||||
// Check fixed rate
|
||||
long fixedRate = TimeUnit.MILLISECONDS.convert(scheduled.fixedRate(), scheduled.timeUnit());
|
||||
long fixedRate = convertToMillis(scheduled.fixedRate(), scheduled.timeUnit());
|
||||
if (fixedRate >= 0) {
|
||||
Assert.isTrue(!processedSchedule, errorMessage);
|
||||
processedSchedule = true;
|
||||
@@ -490,7 +491,7 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||
Assert.isTrue(!processedSchedule, errorMessage);
|
||||
processedSchedule = true;
|
||||
try {
|
||||
fixedRate = TimeUnit.MILLISECONDS.convert(parseDelayAsLong(fixedRateString), scheduled.timeUnit());
|
||||
fixedRate = convertToMillis(fixedRateString, scheduled.timeUnit());
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
throw new IllegalArgumentException(
|
||||
@@ -530,11 +531,19 @@ public class ScheduledAnnotationBeanPostProcessor
|
||||
return new ScheduledMethodRunnable(target, invocableMethod);
|
||||
}
|
||||
|
||||
private static long parseDelayAsLong(String value) throws RuntimeException {
|
||||
if (value.length() > 1 && (isP(value.charAt(0)) || isP(value.charAt(1)))) {
|
||||
private static long convertToMillis(long value, TimeUnit timeUnit) {
|
||||
return TimeUnit.MILLISECONDS.convert(value, timeUnit);
|
||||
}
|
||||
|
||||
private static long convertToMillis(String value, TimeUnit timeUnit) {
|
||||
if (isDurationString(value)) {
|
||||
return Duration.parse(value).toMillis();
|
||||
}
|
||||
return Long.parseLong(value);
|
||||
return convertToMillis(Long.parseLong(value), timeUnit);
|
||||
}
|
||||
|
||||
private static boolean isDurationString(String value) {
|
||||
return (value.length() > 1 && (isP(value.charAt(0)) || isP(value.charAt(1))));
|
||||
}
|
||||
|
||||
private static boolean isP(char ch) {
|
||||
|
||||
Reference in New Issue
Block a user