聊聊springboot2的ScheduledTasksEndpoint

本文主要研究下springboot2的ScheduledTasksEndpoint

实例

注解形式

@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(){

    }
}
复制代码

动态添加

@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 * * ?");
    }
}
复制代码

/actuator/scheduledtasks

{
  "cron": [
    {
      "runnable": {
        "target": "com.example.task.ScheduleTask.cronJob"
      },
      "expression": "0 0 5 * * ?"
    },
    {
      "runnable": {
        "target": "com.example.config.ScheduleConfig$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
    }
  ]
}
复制代码

这里分了三种类型来展示,一个是cron表达式类型,一个是fixedDelay类型,一个是fixedRate类型。

源码解析

ScheduledTasksEndpointAutoConfiguration

spring-boot-actuator-autoconfigure-2.0.0.RELEASE-sources.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) {
		return new ScheduledTasksEndpoint(holders.getIfAvailable(Collections::emptyList));
	}

}
复制代码

可以看到从2.0开始有这个config,这里主要创建了一个ScheduledTasksEndpoint,同时在构造器传入ObjectProvider<List<ScheduledTaskHolder>> holders

ScheduledTasksEndpoint

spring-boot-actuator-2.0.1.RELEASE-sources.jar!/org/springframework/boot/actuate/scheduling/ScheduledTasksEndpoint.java

/**
 * {@link Endpoint} to expose information about an application's scheduled tasks.
 *
 * @author Andy Wilkinson
 * @since 2.0.0
 */
@Endpoint(id = "scheduledtasks")
public class ScheduledTasksEndpoint {

	private final Collection<ScheduledTaskHolder> scheduledTaskHolders;

	public ScheduledTasksEndpoint(Collection<ScheduledTaskHolder> scheduledTaskHolders) {
		this.scheduledTaskHolders = scheduledTaskHolders;
	}

	@ReadOperation
	public ScheduledTasksReport scheduledTasks() {
		Map<TaskType, List<TaskDescription>> 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);
	}

    //......
}
复制代码

这里主要根据scheduledTaskHolders创建ScheduledTasksReport

ScheduledTasksReport

spring-boot-actuator-2.0.0.RELEASE-sources.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<TaskDescription> cron;

		private final List<TaskDescription> fixedDelay;

		private final List<TaskDescription> fixedRate;

		private ScheduledTasksReport(
				Map<TaskType, List<TaskDescription>> 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<TaskDescription> getCron() {
			return this.cron;
		}

		public List<TaskDescription> getFixedDelay() {
			return this.fixedDelay;
		}

		public List<TaskDescription> getFixedRate() {
			return this.fixedRate;
		}

	}
复制代码

这里可以看到report将定时任务归为cron、fixedDelay、fixedRate三类。

SchedulingConfiguration

spring-context-5.0.5.RELEASE-sources.jar!/org/springframework/scheduling/annotation/SchedulingConfiguration.java

/**
 * {@code @Configuration} class that registers a {@link ScheduledAnnotationBeanPostProcessor}
 * bean capable of processing Spring's @{@link Scheduled} annotation.
 *
 * <p>This configuration class is automatically imported when using the
 * {@link EnableScheduling @EnableScheduling} annotation. See
 * {@code @EnableScheduling}'s javadoc for complete 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 ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
		return new ScheduledAnnotationBeanPostProcessor();
	}

}
复制代码

EnableScheduling会启动这个配置,然后创建ScheduledAnnotationBeanPostProcessor

ScheduledAnnotationBeanPostProcessor

spring-context-5.0.5.RELEASE-sources.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 <task:annotation-driven>} XML element, and also by the
 * {@link EnableScheduling @EnableScheduling} annotation.
 *
 * <p>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<ContextRefreshedEvent>, DisposableBean {

	private final ScheduledTaskRegistrar registrar = new ScheduledTaskRegistrar();

	private final Map<Object, Set<ScheduledTask>> scheduledTasks =
			new IdentityHashMap<Object, Set<ScheduledTask>>(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<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 Object postProcessAfterInitialization(final Object bean, String beanName) {
		Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
		if (!this.nonAnnotatedClasses.contains(targetClass)) {
			Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
					(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
						Set<Scheduled> 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();
		}
	}

	//......
}
复制代码
  • getScheduledTasks实现的是ScheduledTaskHolder的接口,用于获取注册的定时任务,它先添加Map<Object, Set<ScheduledTask>> scheduledTasks的values,然后再合并registrar.getScheduledTasks()。这里之所以要合并,主要是系统可能通过ScheduledTaskRegistrar在运行时动态添加/更新/覆盖定时任务

  • 这里postProcessAfterInitialization会去寻找@Scheduled的方法,然后调用processScheduled去注册

  • onApplicationEvent以及afterSingletonsInstantiated会触发finishRegistration,这个方法主要是从实现SchedulingConfigurer接口的方法里头获取动态配置的定时任务信息,即将这里new的一个ScheduledTaskRegistrar传递给SchedulingConfigurer实现类的接口,然后定时任务信息都统一添加到一个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);
			}
}
复制代码

这里将注解的定时任务通过registrar去注册和调度,同时也将这些定时任务添加到registeredTasks中(这里的scheduledTasks类型为Map<Object, Set<ScheduledTask>> ,registeredTasks是这个map的value)

小结

自springboot2.0起,在actuator中新提供了ScheduledTasksEndpoint,默认可以通过/actuator/scheduledtasks来访问当前应用的定时任务信息,非常便利。

doc

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值