我有一个使用“task:scheduler”和“task:scheduled-tasks”元素的应用程序(后者包含“task:scheduled”元素)。这一切都很好。
我正在尝试编写一些内省“应用程序配置”的代码,以获得一些重要信息的简短摘要,例如安排的任务以及他们的日程安排。
我已经有一个有一堆“@Autowired”实例变量的类,所以我可以遍历所有这些。很容易添加“List”来获取所有TaskScheduler对象。我只有两个,我在每个任务中都有一组不同的计划任务。
我在那些TaskScheduler对象中看不到的东西(它们实际上是ThreadPoolTaskScheduler对象)看起来像是一个计划任务列表,所以我猜测计划任务列表会记录在其他地方。
我可以使用哪些对象来反省计划任务集以及它们所在的线程池?
答案 0 :(得分:14)
此功能将在Spring 4.2中提供
https://jira.spring.io/browse/SPR-12748(免责声明:我报告了此问题并为其解决方案提供了代码)。
// Warning there may be more than one ScheduledTaskRegistrar in your
// application context. If this is the case you can autowire a list of
// ScheduledTaskRegistrar instead.
@Autowired
private ScheduledTaskRegistrar scheduledTaskRegistrar;
public List<Task> getScheduledTasks() {
List<Task> result = new ArrayList<Task>();
result.addAll(this.scheduledTaskRegistrar.getTriggerTaskList());
result.addAll(this.scheduledTaskRegistrar.getCronTaskList());
result.addAll(this.scheduledTaskRegistrar.getFixedRateTaskList());
result.addAll(this.scheduledTaskRegistrar.getFixedDelayTaskList());
return result;
}
// You can this inspect the tasks,
// so for example a cron task can be inspected like this:
public List<CronTask> getScheduledCronTasks() {
List<CronTask> cronTaskList = this.scheduledTaskRegistrar.getCronTaskList();
for (CronTask cronTask : cronTaskList) {
System.out.println(cronTask.getExpression);
}
return cronTaskList;
}
如果您使用的是XML中定义的ScheduledMethodRunnable:
<task:scheduled method="run" cron="0 0 12 * * ?" ref="MyObject" />
您可以访问基础目标对象:
ScheduledMethodRunnable scheduledMethodRunnable = (ScheduledMethodRunnable) task.getRunnable();
TargetClass target = (TargetClass) scheduledMethodRunnable.getTarget();
答案 1 :(得分:3)
我有一个前弹簧4.2的片段,因为它仍然处于发布候选级别。
scheduledFuture接口由BlockingQueue中的每个runnable元素实现。
Map<String, ThreadPoolTaskScheduler> schedulers = applicationContext
.getBeansOfType(ThreadPoolTaskScheduler.class);
for (ThreadPoolTaskScheduler scheduler : schedulers.values()) {
ScheduledExecutorService exec = scheduler.getScheduledExecutor();
ScheduledThreadPoolExecutor poolExec = scheduler
.getScheduledThreadPoolExecutor();
BlockingQueue<Runnable> queue = poolExec.getQueue();
Iterator<Runnable> iter = queue.iterator();
while (iter.hasNext()) {
ScheduledFuture<?> future = (ScheduledFuture<?>) iter.next();
future.getDelay(TimeUnit.MINUTES);
Runnable job = iter.next();
logger.debug(MessageFormat.format(":: Task Class is {0}", JobDiscoverer.findRealTask(job)));
}
由于 threadPoolNamePrefix 没有为我返回一个不同的名称,因此有一种反射方式可以获取有关哪个工作类在池中的信息:
public class JobDiscoverer {
private final static Field syncInFutureTask;
private final static Field callableInFutureTask;
private static final Class<? extends Callable> adapterClass;
private static final Field runnableInAdapter;
private static Field reschedulingRunnable;
private static Field targetScheduledMethod;
static {
try {
reschedulingRunnable = Class
.forName(
"org.springframework.scheduling.support.DelegatingErrorHandlingRunnable")
.getDeclaredField("delegate");
reschedulingRunnable.setAccessible(true);
targetScheduledMethod = Class
.forName(
"org.springframework.scheduling.support.ScheduledMethodRunnable")
.getDeclaredField("target");
targetScheduledMethod.setAccessible(true);
callableInFutureTask = Class.forName(
"java.util.concurrent.FutureTask$Sync").getDeclaredField(
"callable");
callableInFutureTask.setAccessible(true);
syncInFutureTask = FutureTask.class.getDeclaredField("sync");
syncInFutureTask.setAccessible(true);
adapterClass = Executors.callable(new Runnable() {
public void run() {
}
}).getClass();
runnableInAdapter = adapterClass.getDeclaredField("task");
runnableInAdapter.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new ExceptionInInitializerError(e);
} catch (SecurityException e) {
throw new PiaRuntimeException(e);
} catch (ClassNotFoundException e) {
throw new PiaRuntimeException(e);
}
}
public static Object findRealTask(Runnable task) {
if (task instanceof FutureTask) {
try {
Object syncAble = syncInFutureTask.get(task);
Object callable = callableInFutureTask.get(syncAble);
if (adapterClass.isInstance(callable)) {
Object reschedulable = runnableInAdapter.get(callable);
Object targetable = reschedulingRunnable.get(reschedulable);
return targetScheduledMethod.get(targetable);
} else {
return callable;
}
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
throw new ClassCastException("Not a FutureTask");
}
答案 2 :(得分:1)
使用基于@Scheduled
的配置,Tobias M的答案无法立即使用。
您可以自动装配仅具有ScheduledTaskRegistrar
方法的ScheduledTaskHolder
来代替自动装配getScheduledTasks()
实例(不适用于基于注释的配置)。
背景:
用于管理ScheduledAnnotationBeanPostProcessor
任务的@Scheduled
有一个内部ScheduledTaskRegistrar
,不能作为bean使用。不过,它确实实现了ScheduledTaskHolder
。
答案 3 :(得分:0)
每个Spring XML元素都有一个对应的BeanDefinitionReader
。对于<task:scheduled-tasks>
,那是ScheduledTasksBeanDefinitionParser
。
这使用BeanDefinitionBuilder
为ContextLifecycleScheduledTaskRegistrar
类型的bean创建BeanDefinition
。您计划的任务将存储在该bean中。
任务将以默认TaskScheduler
或您提供的任务执行。
我已经为您提供了类名,因此如果您需要更精细的细节,可以自己查看源代码。