spring源码深入理解 (一): 定时任务-自定义注解及任务及同一时间多任务执行

spring定时任务-源码解析
spring定时任务-几种使用

前言

利用spring定时任务源码解析出,自己定义注解,达到同一实践多任务的执行

自定义注解

自己做一个自己需要的注解 ,并且可以采用源码中的方式进行管理

  • 将ScheduledAnnotationBeanPostProcessor 类复制 重改名字
  • 定义ScheduledAnnotation 注解
  • postProcessAfterInitialization 中的代码修改
  • 按照自己代码需要修改
@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) {
		if (bean instanceof AopInfrastructureBean || bean instanceof TaskScheduler
				|| bean instanceof ScheduledExecutorService) {
			// Ignore AOP infrastructure such as scoped proxies.
			return bean;
		}

		Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
		if (!this.nonAnnotatedClasses.contains(targetClass)) {
			Map<Method, Set<ScheduledAnnotation>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
					(MethodIntrospector.MetadataLookup<Set<ScheduledAnnotation>>) method -> {
						Set<ScheduledAnnotation> scheduledMethods = AnnotatedElementUtils
								.getMergedRepeatableAnnotations(method, ScheduledAnnotation.class,
										ScheduledAnnotations.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: " + targetClass);
				}
			} else {
				// Non-empty set of methods
				annotatedMethods.forEach((method, scheduledMethods) -> scheduledMethods
						.forEach(scheduled -> processScheduled(scheduled, method, bean)));
				if (logger.isTraceEnabled()) {
					logger.trace(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName + "': "
							+ annotatedMethods);
				}
			}
		}
		return bean;
	}

自定义规则

  • 解析完任务 并自定义好规则进行 将任务放到注册器中;
  • 上篇文章中动态添加任务到注册器中,相对于隔绝了需要管理任务注册器,并且任务注册器会自动删除任务,也不需要自己清理任务,当然自己清理那最好,因为spring的注解解析器,就是自己也会管理这些任务,并在销毁时清理。

	/**
	 * 解析任务并对添加入注册器中
	 * 
	 * @param scheduled
	 * @param method
	 * @param taskList
	 * @param bean
	 */
	protected void processScheduled(ScheduledAnnotation scheduled, Method method, Object bean) {
		try {
			Runnable runnable = createRunnable(bean, method);
			boolean processedSchedule = false;
			String errorMessage = "Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required";

			Set<ScheduledTask> tasks = new LinkedHashSet<>(4);

			// Determine initial delay
			long initialDelay = scheduled.initialDelay();
			String initialDelayString = scheduled.initialDelayString();
			if (StringUtils.hasText(initialDelayString)) {
				Assert.isTrue(initialDelay < 0, "Specify 'initialDelay' or 'initialDelayString', not both");
				if (this.embeddedValueResolver != null) {
					initialDelayString = this.embeddedValueResolver.resolveStringValue(initialDelayString);
				}
				if (StringUtils.hasLength(initialDelayString)) {
					try {
						initialDelay = parseDelayAsLong(initialDelayString);
					} catch (RuntimeException ex) {
						throw new IllegalArgumentException("Invalid initialDelayString value \"" + initialDelayString
								+ "\" - cannot parse into long");
					}
				}
			}

自定义注解一定要屏蔽下面代码

  • 你在使用EnableScheduling 开启spring的注解解释器时,会执行两个任务

在这里插入图片描述

实践问题

  • 多个任务同一时间执行问题
    由于初始化任务 java.util.concurrent .ScheduledThreadPoolExecutor 默认为单线程的线程池
  • 可以采用 在创建的时候自定义核心线程数的大小
    自定义注解器中ScheduledTaskParser设置
    在这里插入图片描述
  • 在实现SchedulingConfigurer 接口里面会获得任务注册器 也可以修改到核心线程数的大小
  • Spring是通过动态创建调度器 所以也可以注册bean的方式

一个任务执行时间如果超过了间隔时间

  • cron表达式 源码定点去执行
  • cron都是按照整点来运行的,比如5秒一次,他会在0,5,10…秒运行,如果任务时间点还没运行结束,那么就会跳过这次任务。

动态添加任务到注册器中 做定时任务

  • Spring自定义ScheduledTaskParser(注解任务解析器)执行任务之前,会调用实现SchedulingConfigurer接口的configureTasks方法,
  • 我们可以自定义实现SchedulingConfigurer
    接口就能做添加任务进去,并且这个bean要交给spring进行管理,并且也可以设置其核心线程数
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

踩踩踩从踩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值