Accessing scheduled tasks in Spring

2019-03-25 02:51发布

问题:

I have a couple of tasks scheduled within Spring's task scheduler:

<task:scheduled-tasks>
    <task:scheduled ref="task1" method="run"
        cron="0 0 */0 * * *" />
    <task:scheduled ref="task2" method="run"
        cron="0 0 */30 * * *" />
</task:scheduled-tasks>

<task:scheduler id="scheduler" pool-size="10" />

How can I access a list of scheduled tasks and retrieve meta-information (e.g the next execution time) from within the application context?

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
ThreadPoolTaskScheduler scheduler = (ThreadPoolTaskScheduler)context.getBean("scheduler");
//... how to continue from here?

回答1:

There is no public API in Spring to do this.

Related:

  • How are Spring <task:scheduled> objects represented at runtime?


回答2:

I just figured this out

start with this to get whats scheduled.

    ThreadPoolTaskScheduler xScheduler = (ThreadPoolTaskScheduler)this.taskScheduler;

    ScheduledThreadPoolExecutor xService = (ScheduledThreadPoolExecutor)xScheduler.getScheduledExecutor();

    BlockingQueue<Runnable> queue = xService.getQueue();
    Object[] scheduledJobs = queue.toArray();

If this array look at instance in debugger to find what you need out.

Then write reflection code like this to get at the hidden API's in Spring and Java. See the set Accessible this is only way to get at these private items. You might need to use different public classes to get at certain private fields, look at api docs and view source on these classes in eclipse.

            Method delayM = obj.getClass().getDeclaredMethod("getDelay", TimeUnit.class);
            delayM.setAccessible(true);
            // delayM = obj.getClass().getDeclaredMethod("getDelay", TimeUnit.class);
            Long delay = (Long)delayM.invoke(obj, new Object[] { tu } );

The trigger and root runnable is in the callable field of this object , instance of ReschedulingRunnable which is not a public class, ask Spring why they did this. You can get the delegate out of DelegatingErrorHandlingRunnable with reflection.