@Scheduled for SpringBoot Source Analysis

Posted by successor on Tue, 03 Mar 2020 02:03:22 +0100

Springboot can accomplish timed tasks by annotating @Scheduled.

Here's a little bit of analysis of its source code

@Service
public class MyScheduled {

    @Scheduled(cron="${time.cron}")
    void paoapaoScheduled() {
        System.out.println("Execute at " + System.currentTimeMillis());
    }
}

Profile 100 seconds

time.cron=*/100 * * * * *

 

Important class ScheduledAnnotationBeanPostProcessor

@Nullable
	private BeanFactory beanFactory;
private void finishRegistration() {
		if (this.scheduler != null) {
			this.registrar.setScheduler(this.scheduler);
		}

		if (this.beanFactory instanceof ListableBeanFactory) {
			Map<String, SchedulingConfigurer> beans =
					((ListableBeanFactory) this.beanFactory).getBeansOfType(SchedulingConfigurer.class);
			List<SchedulingConfigurer> configurers = new ArrayList<>(beans.values());
			AnnotationAwareOrderComparator.sort(configurers);
			for (SchedulingConfigurer configurer : configurers) {
				configurer.configureTasks(this.registrar);
			}
		}

		if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
			Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type");
			try {
				// Search for TaskScheduler bean...
				this.registrar.setTaskScheduler(resolveSchedulerBean(this.beanFactory, TaskScheduler.class, false));
			}
			catch (NoUniqueBeanDefinitionException ex) {
				logger.trace("Could not find unique TaskScheduler bean", ex);
				try {
					this.registrar.setTaskScheduler(resolveSchedulerBean(this.beanFactory, TaskScheduler.class, true));
				}
				catch (NoSuchBeanDefinitionException ex2) {
					if (logger.isInfoEnabled()) {
						logger.info("More than one TaskScheduler bean exists within the context, and " +
								"none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' " +
								"(possibly as an alias); or implement the SchedulingConfigurer interface and call " +
								"ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: " +
								ex.getBeanNamesFound());
					}
				}
			}
			catch (NoSuchBeanDefinitionException ex) {
				logger.trace("Could not find default TaskScheduler bean", ex);
				// Search for ScheduledExecutorService bean next...
				try {
					this.registrar.setScheduler(resolveSchedulerBean(this.beanFactory, ScheduledExecutorService.class, false));
				}
				catch (NoUniqueBeanDefinitionException ex2) {
					logger.trace("Could not find unique ScheduledExecutorService bean", ex2);
					try {
						this.registrar.setScheduler(resolveSchedulerBean(this.beanFactory, ScheduledExecutorService.class, true));
					}
					catch (NoSuchBeanDefinitionException ex3) {
						if (logger.isInfoEnabled()) {
							logger.info("More than one ScheduledExecutorService bean exists within the context, and " +
									"none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' " +
									"(possibly as an alias); or implement the SchedulingConfigurer interface and call " +
									"ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: " +
									ex2.getBeanNamesFound());
						}
					}
				}
				catch (NoSuchBeanDefinitionException ex2) {
					logger.trace("Could not find default ScheduledExecutorService bean", ex2);
					// Giving up -> falling back to default scheduler within the registrar...
					logger.info("No TaskScheduler/ScheduledExecutorService bean found for scheduled processing");
				}
			}
		}

		this.registrar.afterPropertiesSet();
	}

bean 

Find a custom MyScheduled

Find the visible code backwards, then up where it is assigned

if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
			Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type");
			try {
				// Search for TaskScheduler bean...
				this.registrar.setTaskScheduler(resolveSchedulerBean(this.beanFactory, TaskScheduler.class, false));
			}
			catch (NoUniqueBeanDefinitionException ex) {
				logger.trace("Could not find unique TaskScheduler bean", ex);
				try {
					this.registrar.setTaskScheduler(resolveSchedulerBean(this.beanFactory, TaskScheduler.class, true));
				}

 


 

Important class ScheduledThreadPoolExecutor

Reference resources: https://www.jianshu.com/p/502f9952c09b

 

ScheduledThreadPoolExecutor inherits ThreadPoolExecutor, which means that ScheduledThreadPoolExecutor has the basic functions of execute() and submit() to submit asynchronous tasks. The ScheduledThreadPoolExecutor class implements ScheduledExecutor Service, which defines ScheduledThreadPoolExecutor's ability to delay task execution and cycle execution.

Scheduled ThreadPoolExecutor also has two important internal classes: DelayedWorkQueue and Scheduled FutureTask.You can see that DelayedWorkQueue implements the BlockingQueue interface, which is a blocking queue, and ScheduledFutureTask inherits the FutureTask class, which is also used to return the results of asynchronous tasks.

/**
     * @throws RejectedExecutionException {@inheritDoc}
     * @throws NullPointerException       {@inheritDoc}
     */
    public ScheduledFuture<?> schedule(Runnable command,
                                       long delay,
                                       TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        RunnableScheduledFuture<?> t = decorateTask(command,
            new ScheduledFutureTask<Void>(command, null,
                                          triggerTime(delay, unit)));
        delayedExecute(t);
        return t;
    }

Here at schedule:

Increase Timing Task ScheduledTaskRegistrar

protected void scheduleTasks() {
		if (this.taskScheduler == null) {
			this.localExecutor = Executors.newSingleThreadScheduledExecutor();
			this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
		}
		if (this.triggerTasks != null) {
			for (TriggerTask task : this.triggerTasks) {
				addScheduledTask(scheduleTriggerTask(task));
			}
		}
		if (this.cronTasks != null) {
			for (CronTask task : this.cronTasks) {
				addScheduledTask(scheduleCronTask(task));
			}
		}
		if (this.fixedRateTasks != null) {
			for (IntervalTask task : this.fixedRateTasks) {
				addScheduledTask(scheduleFixedRateTask(task));
			}
		}
		if (this.fixedDelayTasks != null) {
			for (IntervalTask task : this.fixedDelayTasks) {
				addScheduledTask(scheduleFixedDelayTask(task));
			}
		}
	}

Traverse arrayList

 

Jump out of refresh

 

How Spring adds the hook function

No hook function registered here is naturally null

Enter Runtime.getRuntime().addShutdownHook(this.shutdownHook);

Finished at last

============================

Trigger Timer

Looking backwards and knowing how to invoke it is actually a reflection of how to execute the above method:

The invoke method is used to dynamically invoke a method of an instance at run time

The Runnable interface is implemented here:

Reflection, Threads, Thread Pool Bottom or these techniques!You need to study this code to get a better understanding of the fundamentals.

 

Extended information: Timed tasks in SpringBoot default to how serial execution sets parallelism

SpringBoot uses the @Scheduled annotation to configure serial, parallel timer tasks

Two ways to implement timed tasks in Spring Boot

1,602 original articles were published. 12,288 were praised. 12,370,000 visits were received.
His message board follow

Topics: SpringBoot Spring