sequence

This article focuses on the ScheduledTasksEndpoint of springboot2

The instance

Annotation form

@Component
public class ScheduleTask {

    @Scheduled(cron = "0, 0, 5 * *?)
    public void cronJob(){

    }

    @Scheduled(fixedDelay = 2*60*1000,initialDelay = 30*1000)
    public void fixedDelayJob(){

    }

    @Scheduled(fixedRate = 5 * 1000)
    public void fixedRatejob() {}}Copy the code

Dynamically add

@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addCronTask(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello"); }},"0 0 6 * *?"); }}Copy the code

/actuator/scheduledtasks

{
  "cron": [{"runnable": {
        "target": "com.example.task.ScheduleTask.cronJob"
      },
      "expression": "0, 0, 5 * *?
    },
    {
      "runnable": {
        "target": "com.example.config.ScheduleConfigThe $1"
      },
      "expression": "0 0 6 * *?"}]."fixedDelay": [{"runnable": {
        "target": "com.example.task.ScheduleTask.fixedDelayJob"
      },
      "initialDelay": 30000,
      "interval": 120000}]."fixedRate": [{"runnable": {
        "target": "com.example.task.ScheduleTask.fixedRatejob"
      },
      "initialDelay": 0."interval": 5000}]}Copy the code

There are three types of cron expression type, fixedDelay type and fixedRate type.

The source code parsing

ScheduledTasksEndpointAutoConfiguration

Spring – the boot – physical – autoconfigure – 2.0.0. RELEASE – sources. The jar! /org/springframework/boot/actuate/autoconfigure/scheduling/ScheduledTasksEndpointAutoConfiguration.java

/**
 * {@link EnableAutoConfiguration Auto-configuration} for {@link ScheduledTasksEndpoint}.
 *
 * @author Andy Wilkinson
 * @since 2.0.0
 */
@Configuration
public class ScheduledTasksEndpointAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	@ConditionalOnEnabledEndpoint
	public ScheduledTasksEndpoint scheduledTasksEndpoint(
			ObjectProvider<List<ScheduledTaskHolder>> holders) {
		returnnew ScheduledTasksEndpoint(holders.getIfAvailable(Collections::emptyList)); }}Copy the code

Can see since 2.0 the config, here basically created a ScheduledTasksEndpoint, at the same time in the constructor to ObjectProvider < List < ScheduledTaskHolder > > holders

ScheduledTasksEndpoint

Spring – the boot – physical – 2.0.1. RELEASE – sources. The jar! /org/springframework/boot/actuate/scheduling/ScheduledTasksEndpoint.java

/**
 * {@link Endpoint} to expose information about an application* * @author Andy Wilkinson * @since 2.0.0 */ @endpoint (id = "scheduledTasks ") public class ScheduledTasksEndpoint { private final Collection
      
        scheduledTaskHolders; public ScheduledTasksEndpoint(Collection
       
         scheduledTaskHolders) { this.scheduledTaskHolders = scheduledTaskHolders; } @ReadOperation public ScheduledTasksReport scheduledTasks() { Map
        
         > descriptionsByType = this.scheduledTaskHolders .stream().flatMap((holder) -> holder.getScheduledTasks().stream()) .map(ScheduledTask::getTask).map(TaskDescription::of) .filter(Objects::nonNull) .collect(Collectors.groupingBy(TaskDescription::getType)); return new ScheduledTasksReport(descriptionsByType); } / /... }
        ,>
       
      Copy the code

Here ScheduledTasksReport is created based on scheduledTaskHolders

ScheduledTasksReport

Spring – the boot – physical – 2.0.0. RELEASE – sources. The jar! /org/springframework/boot/actuate/scheduling/ScheduledTasksEndpoint.java

	/**
	 * A report of an application's scheduled {@link Task Tasks}, primarily intended for * serialization to JSON. */ public static final class ScheduledTasksReport { private final List
      
        cron; private final List
       
         fixedDelay; private final List
        
          fixedRate; private ScheduledTasksReport( Map
         
          > descriptionsByType) { this.cron = descriptionsByType.getOrDefault(TaskType.CRON, Collections.emptyList()); this.fixedDelay = descriptionsByType.getOrDefault(TaskType.FIXED_DELAY, Collections.emptyList()); this.fixedRate = descriptionsByType.getOrDefault(TaskType.FIXED_RATE, Collections.emptyList()); } public List
          
            getCron() { return this.cron; } public List
           
             getFixedDelay() { return this.fixedDelay; } public List
            
              getFixedRate() { return this.fixedRate; }}
            
           
          
         ,>
        
       
      Copy the code

Here you can see that the report classifies scheduled tasks into cron, fixedDelay, and fixedRate.

SchedulingConfiguration

Spring – the context – 5.0.5. RELEASE – sources. The jar! /org/springframework/scheduling/annotation/SchedulingConfiguration.java

/**
 * {@code @Configuration} class that registers a {@link ScheduledAnnotationBeanPostProcessor}
 * bean capable of processing Spring's @{@link Scheduled} annotation. * * 

This configuration class is automatically imported when using the * {@link EnableScheduling @EnableScheduling} annotation. See * {@code @EnableScheduling}'

s javadoc forComplete Usage details. * * @author Chris Beams * @since 3.1 * @see EnableScheduling * @see ScheduledAnnotationBeanPostProcessor */ @Configuration @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class SchedulingConfiguration { @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public ScheduledAnnotationBeanPostProcessorscheduledAnnotationProcessor() { returnnew ScheduledAnnotationBeanPostProcessor(); }}Copy the code

EnableScheduling will start this configuration, and then create ScheduledAnnotationBeanPostProcessor

ScheduledAnnotationBeanPostProcessor

Spring – the context – 5.0.5. RELEASE – sources. The jar! /org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.java

/**
 * Bean post-processor that registers methods annotated with @{@link Scheduled}
 * to be invoked by a {@link org.springframework.scheduling.TaskScheduler} according
 * to the "fixedRate"."fixedDelay", or "cron" expression provided via the annotation.
 *
 * <p>This post-processor is automatically registered by Spring's * {@code 
      
       } XML element, and also by the * {@link EnableScheduling @EnableScheduling} annotation. * * 
       

Autodetects any {@link SchedulingConfigurer} instances in the container, * allowing for customization of the scheduler to be used or for fine-grained * control over task registration (e.g. registration of {@link Trigger} tasks. * See the @{@link EnableScheduling} javadocs for complete usage details. * * @author Mark Fisher * @author Juergen Hoeller * @author Chris Beams * @author Elizabeth Chatman * @since 3.0 * @see Scheduled * @see EnableScheduling * @see SchedulingConfigurer * @see org.springframework.scheduling.TaskScheduler * @see org.springframework.scheduling.config.ScheduledTaskRegistrar * @see AsyncAnnotationBeanPostProcessor */ public class ScheduledAnnotationBeanPostProcessor implements ScheduledTaskHolder, MergedBeanDefinitionPostProcessor, DestructionAwareBeanPostProcessor, Ordered, EmbeddedValueResolverAware, BeanNameAware, BeanFactoryAware, ApplicationContextAware, SmartInitializingSingleton, ApplicationListener , DisposableBean { private final ScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar(); private final Map > scheduledTasks = new IdentityHashMap >(16); /** * Return all currently scheduled tasks, From {@link Scheduled} methods * as well as from programmatic {@link SchedulingConfigurer} interaction. * @since 5.0.2 */ @Override public Set getScheduledTasks() { Set result = new LinkedHashSet<>(); synchronized (this.scheduledTasks) { Collection > allTasks = this.scheduledTasks.values(); for (Set tasks : allTasks) { result.addAll(tasks); } } result.addAll(this.registrar.getScheduledTasks()); return result; } @Override public Object postProcessAfterInitialization(final Object bean, String beanName) { Class targetClass = AopProxyUtils.ultimateTargetClass(bean); if (! this.nonAnnotatedClasses.contains(targetClass)) { Map > annotatedMethods = MethodIntrospector.selectMethods(targetClass, (MethodIntrospector.MetadataLookup >) method -> { Set scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations( method, Scheduled.class, Schedules.class); return (! scheduledMethods.isEmpty() ? scheduledMethods : null); }); if (annotatedMethods.isEmpty()) { this.nonAnnotatedClasses.add(targetClass); if (logger.isTraceEnabled()) { logger.trace("No @Scheduled annotations found on bean class: " + bean.getClass()); } } else { // Non-empty set of methods annotatedMethods.forEach((method, scheduledMethods) -> scheduledMethods.forEach(scheduled -> processScheduled(scheduled, method, bean))); if (logger.isDebugEnabled()) { logger.debug(annotatedMethods.size() + " @Scheduled methods processed on bean ' ,> ,> ,>

" + beanName + "': " + annotatedMethods); } } } return bean; } @Override public void afterSingletonsInstantiated() { // Remove resolved singleton classes from cache this.nonAnnotatedClasses.clear(); if (this.applicationContext == null) { // Not running in an ApplicationContext -> register tasks early... finishRegistration(); } } @Override public void onApplicationEvent(ContextRefreshedEvent event) { if (event.getApplicationContext() == this.applicationContext) { // Running in an ApplicationContext -> register tasks this late... // giving other ContextRefreshedEvent listeners a chance to perform // their work at the same time (e.g. Spring Batch's job registration). finishRegistration(); }} / /... }Copy the code
  • GetScheduledTasks implements the ScheduledTaskHolder interface, which is used to obtain the registered ScheduledTask. It first adds the values of Map<Object, Set<ScheduledTask>> scheduledTasks, Then merge the registrar. GetScheduledTasks (). The main reason for the merger is that the ScheduledTaskRegistrar may use the system to dynamically add/update/override scheduled tasks at runtime

  • PostProcessAfterInitialization here to find out the ways to @ Scheduled, then call processScheduled to register

  • OnApplicationEvent and afterSingletonsInstantiated triggers finishRegistration, this method mainly from the realizing methods of SchedulingConfigurer interface in obtaining dynamic configuration task information regularly, The ScheduledTaskRegistrar is to transfer the new ScheduledTaskRegistrar to the interface of the SchedulingConfigurer implementation class. Then the scheduled task information will be integrated into the ScheduledTaskRegistrar.

processScheduled

protected void processScheduled(Scheduled scheduled, Method method, Object bean) { //... tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone)))); / /... tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay))); / /... tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay))); / /... synchronized (this.scheduledTasks) { Set<ScheduledTask> registeredTasks = this.scheduledTasks.get(bean);if(registeredTasks == null) { registeredTasks = new LinkedHashSet<>(4); this.scheduledTasks.put(bean, registeredTasks); } registeredTasks.addAll(tasks); }}Copy the code

Registrar registrar registrar registrar registrar registrar registrar registrar registrar registrar registrar registrar registrar registrar registrar registrar registrar registrar registrar registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registrar Registry Registry RegisteredTasks is the value of the map.

summary

Since springboot2.0, ScheduledTasksEndpoint is available in the actuator. By default, /actuator/scheduledtasks can access the information of scheduledtasks in the current application, which is very convenient.

doc

  • spring-boot docs