spring定时任务框架Schelduler源码解析

spring定时任务框架Schelduler源码解析

1.第一步@scheduler的注解bean注册、初始化后置处理器 ScheduledAnnotationBeanPostProcessor
关键点初始化spring容器。
(1).获取带有scheduler注解的方法,并转化为 Map<Method, Set>保存带@Scheduler注解的方法作为key,Scheduled保存的定时器参数作为value。
(2)处理步骤一返回带有@scheduler注解方法的信息集合Map<Method, Set>,然后把任务根据Scheduled信息区分成CronTask(带cron表达式的任务)、FixedDelayTask(带延迟的任务)和FixedRateTask(固定频率的任务)分别添加到ScheduledTaskRegistrar任务处理中心。
(3).任务注册处理中心ScheduledTaskRegistrar,继承了InitializingBean接口,初始化时调用afterPropertiesSet方法完成ConcurrentTaskScheduler初始化taskScheduler,任务归类,传给ConcurrentTaskScheduler处理任务。
(4).任务交给ConcurrentTaskScheduler执行器,并获取future并行处理工具类,ConcurrentTaskScheduler执行器把任务交给ScheduledThreadPoolExecutor延时线程池执行器处理,ScheduledThreadPoolExecutor把任务放入延迟任务队列。
(5).消费任务会调用任务ScheduledFutureTask的run方法,检查是否是周期任务,周期任务并计算下一次任务删除之前的旧任务并重新加入队列。等待消费者消费队列

2.核心代码讲解

ScheduledAnnotationBeanPostProcessor类
初始化spring容器后置处理器ScheduledAnnotationBeanPostProcessor,获取带有scheduler注解的方法,并转化为 Map<Method, Set>保存带@Scheduler注解的方法作为key,Scheduled保存的定时器参数作为value,处理步骤一返回带有@scheduler注解方法的信息集合Map<Method, Set>,然后把任务根据Scheduled信息区分成CronTask(带cron表达式的任务)、FixedDelayTask(带延迟的任务)和FixedRateTask(固定频率的任务)分别添加到ScheduledTaskRegistrar任务注册处理中心。

public Object postProcessAfterInitialization(Object bean, String beanName) {
        Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
        if (!this.nonAnnotatedClasses.contains(targetClass)) {
            Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass, (method) -> {
                 **//获取带有scheduler注解的方法,并转化为 Map<Method, Set<Scheduled>>保存带@Scheduler注解的方法作为key,Scheduled保存的定时器参数作为value**
                Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);  
                return !scheduledMethods.isEmpty() ? scheduledMethods : null;
            });
            if (annotatedMethods.isEmpty()) {
                this.nonAnnotatedClasses.add(targetClass);
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("No @Scheduled annotations found on bean class: " + bean.getClass());
                }
            } else {
                annotatedMethods.forEach((method, scheduledMethods) -> {
                    scheduledMethods.forEach((scheduled) -> {
                        this.processScheduled(scheduled, method, bean);  **//如果annotatedMethods不为空则处理带有schduler注解的方法**
                    });
                });
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName + "': " + annotatedMethods);
                }
            }
        }

        return bean;
    }
**处理带有@schedluer注解的方法**
protected void processScheduled(Scheduled scheduled, Method method, Object bean) {
        try {
            Assert.isTrue(method.getParameterCount() == 0, "Only no-arg methods may be annotated with @Scheduled");
            Method invocableMethod = AopUtils.selectInvocableMethod(method, bean.getClass());
            Runnable runnable = new ScheduledMethodRunnable(bean, invocableMethod);
            boolean processedSchedule = false;
            String errorMessage = "Exactly one of the 'cron', 'fixedDelay(String)', or 'fixedRate(String)' attributes is required";
            Set<ScheduledTask> tasks = new LinkedHashSet(4);
            long initialDelay = scheduled.initialDelay();
            String initialDelayString = scheduled.initialDelayString();
            if (StringUtils.hasText(initialDelayString)) {
                Assert.isTrue(initialDelay < 0L, "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 var25) {
                        throw new IllegalArgumentException("Invalid initialDelayString value \"" + initialDelayString + "\" - cannot parse into long");
                    }
                }
            }

            String cron = scheduled.cron();
            if (StringUtils.hasText(cron)) {
                String zone = scheduled.zone();
                if (this.embeddedValueResolver != null) {
                    cron = this.embeddedValueResolver.resolveStringValue(cron);
                    zone = this.embeddedValueResolver.resolveStringValue(zone);
                }

                if (StringUtils.hasLength(cron)) {
                    Assert.isTrue(initialDelay == -1L, "'initialDelay' not supported for cron triggers");
                    processedSchedule = true;
                    TimeZone timeZone;
                    if (StringUtils.hasText(zone)) {
                        timeZone = StringUtils.parseTimeZoneString(zone);
                    } else {
                        timeZone = TimeZone.getDefault();
                    }
					**//向任务注册中心注册CronTask任务**
                    tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));
                }
            }

            if (initialDelay < 0L) {
                initialDelay = 0L;
            }

            long fixedDelay = scheduled.fixedDelay();
            if (fixedDelay >= 0L) {
                Assert.isTrue(!processedSchedule, errorMessage);
                processedSchedule = true;
                **//向任务注册中心注册FixedDelayTask任务**
                tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay))); 
            }

            String fixedDelayString = scheduled.fixedDelayString();
            if (StringUtils.hasText(fixedDelayString)) {
                if (this.embeddedValueResolver != null) {
                    fixedDelayString = this.embeddedValueResolver.resolveStringValue(fixedDelayString);
                }

                if (StringUtils.hasLength(fixedDelayString)) {
                    Assert.isTrue(!processedSchedule, errorMessage);
                    processedSchedule = true;

                    try {
                        fixedDelay = parseDelayAsLong(fixedDelayString);
                    } catch (RuntimeException var24) {
                        throw new IllegalArgumentException("Invalid fixedDelayString value \"" + fixedDelayString + "\" - cannot parse into long");
                    }

                    tasks.add(this.registrar.scheduleFixedDelayTask(new FixedDelayTask(runnable, fixedDelay, initialDelay)));**//向任务注册中心注册FixedDelayTask任务**
                }
            }

            long fixedRate = scheduled.fixedRate();
            if (fixedRate >= 0L) {
                Assert.isTrue(!processedSchedule, errorMessage);
                processedSchedule = true;
                **//向任务注册中心注册FixedRateTask任务**
                tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay)));
            }

            String fixedRateString = scheduled.fixedRateString();
            if (StringUtils.hasText(fixedRateString)) {
                if (this.embeddedValueResolver != null) {
                    fixedRateString = this.embeddedValueResolver.resolveStringValue(fixedRateString);
                }

                if (StringUtils.hasLength(fixedRateString)) {
                    Assert.isTrue(!processedSchedule, errorMessage);
                    processedSchedule = true;

                    try {
                        fixedRate = parseDelayAsLong(fixedRateString);
                    } catch (RuntimeException var23) {
                        throw new IllegalArgumentException("Invalid fixedRateString value \"" + fixedRateString + "\" - cannot parse into long");
                    }

                    tasks.add(this.registrar.scheduleFixedRateTask(new FixedRateTask(runnable, fixedRate, initialDelay)));
                }
            }

            Assert.isTrue(processedSchedule, errorMessage);
            Map var19 = this.scheduledTasks;
            synchronized(this.scheduledTasks) {
                Set<ScheduledTask> registeredTasks = (Set)this.scheduledTasks.get(bean);
                if (registeredTasks == null) {
                    registeredTasks = new LinkedHashSet(4);
                    this.scheduledTasks.put(bean, registeredTasks);
                }
                ((Set)registeredTasks).addAll(tasks);
            }
        } catch (IllegalArgumentException var26) {
            throw new IllegalStateException("Encountered invalid @Scheduled method '" + method.getName() + "': " + var26.getMessage());
        }
    }

ScheduledTaskRegistrar任务处理中心
任务注册处理中心ScheduledTaskRegistrar,继承了InitializingBean接口,初始化时调用afterPropertiesSet方法完成ConcurrentTaskScheduler初始化taskScheduler,任务归类,传给ConcurrentTaskScheduler处理任务。

public void afterPropertiesSet() {
        this.scheduleTasks();    //初始化任务执行器,并添加任务且执行调度
    }

    protected void scheduleTasks() {
        if (this.taskScheduler == null) {
            this.localExecutor = Executors.newSingleThreadScheduledExecutor();
            this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
        }

        Iterator var1;
        if (this.triggerTasks != null) {
            var1 = this.triggerTasks.iterator();

            while(var1.hasNext()) {
                TriggerTask task = (TriggerTask)var1.next();
                this.addScheduledTask(this.scheduleTriggerTask(task));
            }
        }

        if (this.cronTasks != null) {
            var1 = this.cronTasks.iterator();

            while(var1.hasNext()) {
                CronTask task = (CronTask)var1.next();
                this.addScheduledTask(this.scheduleCronTask(task));
            }
        }

        IntervalTask task;
        if (this.fixedRateTasks != null) {
            var1 = this.fixedRateTasks.iterator();

            while(var1.hasNext()) {
                task = (IntervalTask)var1.next();
                this.addScheduledTask(this.scheduleFixedRateTask(task));
            }
        }

        if (this.fixedDelayTasks != null) {
            var1 = this.fixedDelayTasks.iterator();

            while(var1.hasNext()) {
                task = (IntervalTask)var1.next();
                this.addScheduledTask(this.scheduleFixedDelayTask(task));
            }
        }

    }

@Nullable
    public ScheduledTask scheduleFixedRateTask(FixedRateTask task) {
        ScheduledTask scheduledTask = (ScheduledTask)this.unresolvedTasks.remove(task);
        boolean newTask = false;
        if (scheduledTask == null) {
            scheduledTask = new ScheduledTask(task);
            newTask = true;
        }

        if (this.taskScheduler != null) {
            if (task.getInitialDelay() > 0L) {
                Date startTime = new Date(System.currentTimeMillis() + task.getInitialDelay());
                **//任务交给ConcurrentTaskScheduler执行器并过去future并行处理工具类**
                scheduledTask.future = this.taskScheduler.scheduleAtFixedRate(task.getRunnable(), startTime, task.getInterval()); 
            } else {
            	***//任务交给ConcurrentTaskScheduler执行器并过去future并行处理工具类*
                scheduledTask.future = this.taskScheduler.scheduleAtFixedRate(task.getRunnable(), task.getInterval()); 
            }
        } else {
            this.addFixedRateTask(task);
            this.unresolvedTasks.put(task, scheduledTask);
        }

        return newTask ? scheduledTask : null;
    }
    

ConcurrentTaskScheduler并行任务执行器执行任务
任务交给ConcurrentTaskScheduler执行器并过去future并行处理工具类,ConcurrentTaskScheduler执行器把任务交给ScheduledThreadPoolExecutor延时线程池执行器处理,ScheduledThreadPoolExecutor把任务放入延迟任务队列。


ConcurrentTaskScheduler并行任务执行器执行任务
public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
        long initialDelay = startTime.getTime() - System.currentTimeMillis();

        try {
        	**//交给ScheduledThreadPoolExecutor延时线程池执行器处理**
            return this.scheduledExecutor.scheduleAtFixedRate(this.decorateTask(task, true), initialDelay, period, TimeUnit.MILLISECONDS); 
        } catch (RejectedExecutionException var8) {
            throw new TaskRejectedException("Executor [" + this.scheduledExecutor + "] did not accept task: " + task, var8);
        }
    }
    
**ScheduledThreadPoolExecutor类处理FixedRatTask任务放任务到延迟队列**
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                                  long initialDelay,
                                                  long period,
                                                  TimeUnit unit) {
        if (command == null || unit == null)
            throw new NullPointerException();
        if (period <= 0)
            throw new IllegalArgumentException();
            **//转化成ScheduledFutureTask(盛放任务的延迟队列,和下一次任务信息)**
        ScheduledFutureTask<Void> sft =
            new ScheduledFutureTask<Void>(command,
                                          null,
                                          triggerTime(initialDelay, unit),
                                          unit.toNanos(period));    
        RunnableScheduledFuture<Void> t = decorateTask(command, sft); 
        sft.outerTask = t;  //获取下一次任务
        delayedExecute(t);  //执行下一次任务
        return t;
    }

ScheduledFutureTask任务对象
消费任务会调用任务ScheduledFutureTask的run方法,检查是否是周期任务,周期任务并计算下一次任务删除之前的旧任务并重新加入队列。等待消费者消费队列。

/**
         * Overrides FutureTask version so as to reset/requeue if periodic.
         */
        public void run() {
            boolean periodic = isPeriodic();
            if (!canRunInCurrentRunState(periodic))
                cancel(false);
            else if (!periodic)
                ScheduledFutureTask.super.run();  //不是周期性任务
            else if (ScheduledFutureTask.super.runAndReset()) { //周期性任务
                setNextRunTime(); //设置下一次任务事件
                reExecutePeriodic(outerTask); // 删除延时任务,并把新任务放入延迟队列中
            }
        }

/**
     * Requeues a periodic task unless current run state precludes it.
     * Same idea as delayedExecute except drops task rather than rejecting.
     *
     * @param task the task
     */
    void reExecutePeriodic(RunnableScheduledFuture<?> task) {
        if (canRunInCurrentRunState(true)) {
            super.getQueue().add(task);
            if (!canRunInCurrentRunState(true) && remove(task))
                task.cancel(false);
            else
                ensurePrestart();
        }
    }

作者相关文章:
JAVA中的CAS和ABA问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值