Scheduled task introspection through ScheduledTaskHolder interface

Issue: SPR-15982
This commit is contained in:
Juergen Hoeller
2017-11-06 18:36:39 +01:00
parent 9511d29adb
commit ffd6eff369
12 changed files with 272 additions and 37 deletions

View File

@@ -60,8 +60,10 @@ import org.springframework.lang.Nullable;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.IntervalTask;
import org.springframework.scheduling.config.FixedDelayTask;
import org.springframework.scheduling.config.FixedRateTask;
import org.springframework.scheduling.config.ScheduledTask;
import org.springframework.scheduling.config.ScheduledTaskHolder;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.scheduling.support.ScheduledMethodRunnable;
@@ -96,7 +98,7 @@ import org.springframework.util.StringValueResolver;
* @see AsyncAnnotationBeanPostProcessor
*/
public class ScheduledAnnotationBeanPostProcessor
implements MergedBeanDefinitionPostProcessor, DestructionAwareBeanPostProcessor,
implements ScheduledTaskHolder, MergedBeanDefinitionPostProcessor, DestructionAwareBeanPostProcessor,
Ordered, EmbeddedValueResolverAware, BeanNameAware, BeanFactoryAware, ApplicationContextAware,
SmartInitializingSingleton, ApplicationListener<ContextRefreshedEvent>, DisposableBean {
@@ -400,7 +402,7 @@ public class ScheduledAnnotationBeanPostProcessor
if (fixedDelay >= 0) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
tasks.add(this.registrar.scheduleFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay)));
tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay)));
}
String fixedDelayString = scheduled.fixedDelayString();
if (StringUtils.hasText(fixedDelayString)) {
@@ -417,7 +419,7 @@ public class ScheduledAnnotationBeanPostProcessor
throw new IllegalArgumentException(
"Invalid fixedDelayString value \"" + fixedDelayString + "\" - cannot parse into long");
}
tasks.add(this.registrar.scheduleFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay)));
tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay)));
}
}
@@ -426,7 +428,7 @@ public class ScheduledAnnotationBeanPostProcessor
if (fixedRate >= 0) {
Assert.isTrue(!processedSchedule, errorMessage);
processedSchedule = true;
tasks.add(this.registrar.scheduleFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay)));
tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay)));
}
String fixedRateString = scheduled.fixedRateString();
if (StringUtils.hasText(fixedRateString)) {
@@ -443,7 +445,7 @@ public class ScheduledAnnotationBeanPostProcessor
throw new IllegalArgumentException(
"Invalid fixedRateString value \"" + fixedRateString + "\" - cannot parse into integer");
}
tasks.add(this.registrar.scheduleFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay)));
tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay)));
}
}
@@ -467,6 +469,24 @@ public class ScheduledAnnotationBeanPostProcessor
}
/**
* Return all currently scheduled tasks, from {@link Scheduled} methods
* as well as from programmatic {@link SchedulingConfigurer} interaction.
* @since 5.0.2
*/
@Override
public Set<ScheduledTask> getScheduledTasks() {
Set<ScheduledTask> result = new LinkedHashSet<>();
synchronized (this.scheduledTasks) {
Collection<Set<ScheduledTask>> allTasks = this.scheduledTasks.values();
for (Set<ScheduledTask> tasks : allTasks) {
result.addAll(tasks);
}
}
result.addAll(this.registrar.getScheduledTasks());
return result;
}
@Override
public void postProcessBeforeDestruction(Object bean, String beanName) {
Set<ScheduledTask> tasks;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2017 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.
@@ -26,8 +26,7 @@ import org.springframework.scheduling.support.CronTrigger;
* @author Chris Beams
* @since 3.2
* @see org.springframework.scheduling.annotation.Scheduled#cron()
* @see ScheduledTaskRegistrar#setCronTasksList(java.util.List)
* @see org.springframework.scheduling.TaskScheduler
* @see ScheduledTaskRegistrar#addCronTask(CronTask)
*/
public class CronTask extends TriggerTask {
@@ -37,7 +36,7 @@ public class CronTask extends TriggerTask {
/**
* Create a new {@code CronTask}.
* @param runnable the underlying task to execute
* @param expression cron expression defining when the task should be executed
* @param expression the cron expression defining when the task should be executed
*/
public CronTask(Runnable runnable, String expression) {
this(runnable, new CronTrigger(expression));
@@ -54,6 +53,9 @@ public class CronTask extends TriggerTask {
}
/**
* Return the cron expression defining when the task should be executed.
*/
public String getExpression() {
return this.expression;
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.scheduling.config;
/**
* Specialization of {@link IntervalTask} for fixed-delay semantics.
*
* @author Juergen Hoeller
* @since 5.0.2
* @see org.springframework.scheduling.annotation.Scheduled#fixedDelay()
* @see ScheduledTaskRegistrar#addFixedDelayTask(IntervalTask)
*/
public class FixedDelayTask extends IntervalTask {
/**
* Create a new {@code FixedDelayTask}.
* @param runnable the underlying task to execute
* @param interval how often in milliseconds the task should be executed
* @param initialDelay the initial delay before first execution of the task
*/
public FixedDelayTask(Runnable runnable, long interval, long initialDelay) {
super(runnable, interval, initialDelay);
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.scheduling.config;
/**
* Specialization of {@link IntervalTask} for fixed-rate semantics.
*
* @author Juergen Hoeller
* @since 5.0.2
* @see org.springframework.scheduling.annotation.Scheduled#fixedRate()
* @see ScheduledTaskRegistrar#addFixedRateTask(IntervalTask)
*/
public class FixedRateTask extends IntervalTask {
/**
* Create a new {@code FixedRateTask}.
* @param runnable the underlying task to execute
* @param interval how often in milliseconds the task should be executed
* @param initialDelay the initial delay before first execution of the task
*/
public FixedRateTask(Runnable runnable, long interval, long initialDelay) {
super(runnable, interval, initialDelay);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2017 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.
@@ -23,11 +23,8 @@ package org.springframework.scheduling.config;
*
* @author Chris Beams
* @since 3.2
* @see org.springframework.scheduling.annotation.Scheduled#fixedRate()
* @see org.springframework.scheduling.annotation.Scheduled#fixedDelay()
* @see ScheduledTaskRegistrar#setFixedRateTasksList(java.util.List)
* @see ScheduledTaskRegistrar#setFixedDelayTasksList(java.util.List)
* @see org.springframework.scheduling.TaskScheduler
* @see ScheduledTaskRegistrar#addFixedRateTask(IntervalTask)
* @see ScheduledTaskRegistrar#addFixedDelayTask(IntervalTask)
*/
public class IntervalTask extends Task {
@@ -40,7 +37,7 @@ public class IntervalTask extends Task {
* Create a new {@code IntervalTask}.
* @param runnable the underlying task to execute
* @param interval how often in milliseconds the task should be executed
* @param initialDelay initial delay before first execution of the task
* @param initialDelay the initial delay before first execution of the task
*/
public IntervalTask(Runnable runnable, long interval, long initialDelay) {
super(runnable);
@@ -58,10 +55,16 @@ public class IntervalTask extends Task {
}
/**
* Return how often in milliseconds the task should be executed.
*/
public long getInterval() {
return this.interval;
}
/**
* Return the initial delay before first execution of the task.
*/
public long getInitialDelay() {
return this.initialDelay;
}

View File

@@ -21,24 +21,37 @@ import java.util.concurrent.ScheduledFuture;
import org.springframework.lang.Nullable;
/**
* A representation of a scheduled task,
* A representation of a scheduled task at runtime,
* used as a return value for scheduling methods.
*
* @author Juergen Hoeller
* @since 4.3
* @see ScheduledTaskRegistrar#scheduleTriggerTask
* @see ScheduledTaskRegistrar#scheduleFixedRateTask
* @see ScheduledTaskRegistrar#scheduleCronTask(CronTask)
* @see ScheduledTaskRegistrar#scheduleFixedRateTask(FixedRateTask)
* @see ScheduledTaskRegistrar#scheduleFixedDelayTask(FixedDelayTask)
*/
public final class ScheduledTask {
private final Task task;
@Nullable
volatile ScheduledFuture<?> future;
ScheduledTask() {
ScheduledTask(Task task) {
this.task = task;
}
/**
* Return the underlying task (typically a {@link CronTask},
* {@link FixedRateTask} or {@link FixedDelayTask}).
* @since 5.0.2
*/
public Task getTask() {
return this.task;
}
/**
* Trigger cancellation of this scheduled task.
*/
@@ -49,4 +62,9 @@ public final class ScheduledTask {
}
}
@Override
public String toString() {
return this.task.toString();
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.scheduling.config;
import java.util.Set;
/**
* Common interface for exposing locally scheduled tasks.
*
* @author Juergen Hoeller
* @since 5.0.2
* @see ScheduledTaskRegistrar
* @see org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor
*/
public interface ScheduledTaskHolder {
/**
* Return an overview of the tasks that have been scheduled by this instance.
*/
Set<ScheduledTask> getScheduledTasks();
}

View File

@@ -54,7 +54,7 @@ import org.springframework.util.CollectionUtils;
* @see org.springframework.scheduling.annotation.EnableAsync
* @see org.springframework.scheduling.annotation.SchedulingConfigurer
*/
public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean {
public class ScheduledTaskRegistrar implements ScheduledTaskHolder, InitializingBean, DisposableBean {
@Nullable
private TaskScheduler taskScheduler;
@@ -333,8 +333,8 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
}
/**
* Schedule all registered tasks against the underlying {@linkplain
* #setTaskScheduler(TaskScheduler) task scheduler}.
* Schedule all registered tasks against the underlying
* {@linkplain #setTaskScheduler(TaskScheduler) task scheduler}.
*/
protected void scheduleTasks() {
if (this.taskScheduler == null) {
@@ -381,7 +381,7 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
ScheduledTask scheduledTask = this.unresolvedTasks.remove(task);
boolean newTask = false;
if (scheduledTask == null) {
scheduledTask = new ScheduledTask();
scheduledTask = new ScheduledTask(task);
newTask = true;
}
if (this.taskScheduler != null) {
@@ -406,7 +406,7 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
ScheduledTask scheduledTask = this.unresolvedTasks.remove(task);
boolean newTask = false;
if (scheduledTask == null) {
scheduledTask = new ScheduledTask();
scheduledTask = new ScheduledTask(task);
newTask = true;
}
if (this.taskScheduler != null) {
@@ -425,13 +425,29 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
* @return a handle to the scheduled task, allowing to cancel it
* (or {@code null} if processing a previously registered task)
* @since 4.3
* @deprecated as of 5.0.2, in favor of {@link #scheduleFixedRateTask(FixedRateTask)}
*/
@Deprecated
@Nullable
public ScheduledTask scheduleFixedRateTask(IntervalTask task) {
FixedRateTask taskToUse = (task instanceof FixedRateTask ? (FixedRateTask) task :
new FixedRateTask(task.getRunnable(), task.getInterval(), task.getInitialDelay()));
return scheduleFixedRateTask(taskToUse);
}
/**
* Schedule the specified fixed-rate task, either right away if possible
* or on initialization of the scheduler.
* @return a handle to the scheduled task, allowing to cancel it
* (or {@code null} if processing a previously registered task)
* @since 5.0.2
*/
@Nullable
public ScheduledTask scheduleFixedRateTask(FixedRateTask task) {
ScheduledTask scheduledTask = this.unresolvedTasks.remove(task);
boolean newTask = false;
if (scheduledTask == null) {
scheduledTask = new ScheduledTask();
scheduledTask = new ScheduledTask(task);
newTask = true;
}
if (this.taskScheduler != null) {
@@ -458,13 +474,29 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
* @return a handle to the scheduled task, allowing to cancel it
* (or {@code null} if processing a previously registered task)
* @since 4.3
* @deprecated as of 5.0.2, in favor of {@link #scheduleFixedDelayTask(FixedDelayTask)}
*/
@Deprecated
@Nullable
public ScheduledTask scheduleFixedDelayTask(IntervalTask task) {
FixedDelayTask taskToUse = (task instanceof FixedDelayTask ? (FixedDelayTask) task :
new FixedDelayTask(task.getRunnable(), task.getInterval(), task.getInitialDelay()));
return scheduleFixedDelayTask(taskToUse);
}
/**
* Schedule the specified fixed-delay task, either right away if possible
* or on initialization of the scheduler.
* @return a handle to the scheduled task, allowing to cancel it
* (or {@code null} if processing a previously registered task)
* @since 5.0.2
*/
@Nullable
public ScheduledTask scheduleFixedDelayTask(FixedDelayTask task) {
ScheduledTask scheduledTask = this.unresolvedTasks.remove(task);
boolean newTask = false;
if (scheduledTask == null) {
scheduledTask = new ScheduledTask();
scheduledTask = new ScheduledTask(task);
newTask = true;
}
if (this.taskScheduler != null) {
@@ -486,6 +518,19 @@ public class ScheduledTaskRegistrar implements InitializingBean, DisposableBean
}
/**
* Return all locally registered tasks that have been scheduled by this registrar.
* @since 5.0.2
* @see #addTriggerTask
* @see #addCronTask
* @see #addFixedRateTask
* @see #addFixedDelayTask
*/
@Override
public Set<ScheduledTask> getScheduledTasks() {
return Collections.unmodifiableSet(this.scheduledTasks);
}
@Override
public void destroy() {
for (ScheduledTask task : this.scheduledTasks) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2017 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,11 +16,14 @@
package org.springframework.scheduling.config;
import org.springframework.util.Assert;
/**
* Holder class defining a {@code Runnable} to be executed as a task, typically at a
* scheduled time or interval. See subclass hierarchy for various scheduling approaches.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.2
*/
public class Task {
@@ -30,14 +33,25 @@ public class Task {
/**
* Create a new {@code Task}.
* @param runnable the underlying task to execute.
* @param runnable the underlying task to execute
*/
public Task(Runnable runnable) {
Assert.notNull(runnable, "Runnable must not be null");
this.runnable = runnable;
}
/**
* Return the underlying task.
*/
public Runnable getRunnable() {
return runnable;
return this.runnable;
}
@Override
public String toString() {
return this.runnable.toString();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.config;
import org.springframework.scheduling.Trigger;
import org.springframework.util.Assert;
/**
* {@link Task} implementation defining a {@code Runnable} to be executed
@@ -24,8 +25,7 @@ import org.springframework.scheduling.Trigger;
*
* @author Chris Beams
* @since 3.2
* @see Trigger#nextExecutionTime(org.springframework.scheduling.TriggerContext)
* @see ScheduledTaskRegistrar#setTriggerTasksList(java.util.List)
* @see ScheduledTaskRegistrar#addTriggerTask(TriggerTask)
* @see org.springframework.scheduling.TaskScheduler#schedule(Runnable, Trigger)
*/
public class TriggerTask extends Task {
@@ -40,10 +40,14 @@ public class TriggerTask extends Task {
*/
public TriggerTask(Runnable runnable, Trigger trigger) {
super(runnable);
Assert.notNull(trigger, "Trigger must not be null");
this.trigger = trigger;
}
/**
* Return the associated trigger.
*/
public Trigger getTrigger() {
return this.trigger;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2017 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.
@@ -72,4 +72,9 @@ public class ScheduledMethodRunnable implements Runnable {
}
}
@Override
public String toString() {
return this.method.getDeclaringClass().getName() + "." + this.method.getName();
}
}