quartz的使用(二.基本过程)

1.关于各个要素的创建,SchedulerFactoryBean,CronTriggerFactoryBean及JobDetailFactoryBean全部实现spring中的FactoryBean<CronTrigger>, BeanNameAware, InitializingBean用于生成各自的实例

1.1.JobDetailFactoryBean 使用JobDetail的实现类JobDetailImpl生成JobDetail实例

public void afterPropertiesSet() {
                if (this.name == null) {
                    this.name = this.beanName;
                }
                if (this.group == null) {
                    this.group = Scheduler.DEFAULT_GROUP;
                }
                if (this.applicationContextJobDataKey != null) {
                    if (this.applicationContext == null) {
                        throw new IllegalStateException(
                            "JobDetailBean needs to be set up in an ApplicationContext " +
                            "to be able to handle an 'applicationContextJobDataKey'");
                    }
                    getJobDataMap().put(this.applicationContextJobDataKey, this.applicationContext);
                }

                JobDetailImpl jdi = new JobDetailImpl();
                jdi.setName(this.name);
                jdi.setGroup(this.group);
                jdi.setJobClass((Class) this.jobClass);
                jdi.setJobDataMap(this.jobDataMap);
                jdi.setDurability(this.durability);
                jdi.setRequestsRecovery(this.requestsRecovery);
                jdi.setDescription(this.description);
                this.jobDetail = jdi;
            }

1.2.CronTriggerFactoryBean使用Trigger的实现类CronTriggerImpl生成Trigger实例

public void afterPropertiesSet() throws ParseException {
                if (this.name == null) {
                    this.name = this.beanName;
                }
                if (this.group == null) {
                    this.group = Scheduler.DEFAULT_GROUP;
                }
                if (this.jobDetail != null) {
                    this.jobDataMap.put("jobDetail", this.jobDetail);
                }
                if (this.startDelay > 0 || this.startTime == null) {
                    this.startTime = new Date(System.currentTimeMillis() + this.startDelay);
                }
                if (this.timeZone == null) {
                    this.timeZone = TimeZone.getDefault();
                }

                CronTriggerImpl cti = new CronTriggerImpl();
                cti.setName(this.name);
                cti.setGroup(this.group);
                if (this.jobDetail != null) {
                    cti.setJobKey(this.jobDetail.getKey());
                }
                cti.setJobDataMap(this.jobDataMap);
                cti.setStartTime(this.startTime);
                cti.setCronExpression(this.cronExpression);
                cti.setTimeZone(this.timeZone);
                cti.setCalendarName(this.calendarName);
                cti.setPriority(this.priority);
                cti.setMisfireInstruction(this.misfireInstruction);
                cti.setDescription(this.description);
                this.cronTrigger = cti;
            }

1.3.SchedulerFactoryBean 使用StdSchedulerFacotory(通过配置文件来设置Scheduler的各项参数,还有一种DirectSchedulerFactory主要通过硬编码的不做介绍)
创建Scheduler的实现StdScheduler,然后将所有功能托管给QuartzScheduler,实际所有功能通过QuartzScheduler实例进行实现

public void afterPropertiesSet() throws Exception {
                ...

                // Create SchedulerFactory instance...
                SchedulerFactory schedulerFactory = BeanUtils.instantiateClass(this.schedulerFactoryClass);
                initSchedulerFactory(schedulerFactory);

                ...

                // Get Scheduler instance from SchedulerFactory.
                try {
                    this.scheduler = createScheduler(schedulerFactory, this.schedulerName);
                    populateSchedulerContext();

                    if (!this.jobFactorySet && !(this.scheduler instanceof RemoteScheduler)) {
                        // Use AdaptableJobFactory as default for a local Scheduler, unless when
                        // explicitly given a null value through the "jobFactory" bean property.
                        this.jobFactory = new AdaptableJobFactory();
                    }
                    if (this.jobFactory != null) {
                        if (this.jobFactory instanceof SchedulerContextAware) {
                            ((SchedulerContextAware) this.jobFactory).setSchedulerContext(this.scheduler.getContext());
                        }
                        this.scheduler.setJobFactory(this.jobFactory);
                    }
                }

                ...

                registerListeners();
                registerJobsAndTriggers();
            }

1.4 启动QuartzScheduler.start(),通过spring的AbstractApplicationContext中的refresh()方法启动

 2.任务运行过程

 2.1创建QuartzScheduler时创建调度器主线程并运行

public QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, @Deprecated long dbRetryInterval)
                throws SchedulerException {
                
                ....

                this.schedThread = new QuartzSchedulerThread(this, resources);
                ThreadExecutor schedThreadExecutor = resources.getThreadExecutor();
                schedThreadExecutor.execute(this.schedThread);
                
                ...
            }

2.2 QuartzSchedulerThread运行

public void run() {
                boolean lastAcquireFailed = false;

                while (!halted.get()) {
                    try {
                        // check if we're supposed to pause...
                        synchronized (sigLock) {
                            while (paused && !halted.get()) {
                                try {
                                    //等待直到togglePause(false)被调用,在QuartzScheduler.start()调用以后
                                    sigLock.wait(1000L);
                                } catch (InterruptedException ignore) {
                                }
                            }

                            if (halted.get()) {
                                break;
                            }
                        }
                        //获取可用线程的数量,获取线程池,没有可用线程时等待
                        int availThreadCount = qsRsrcs.getThreadPool().blockForAvailableThreads();
                        if(availThreadCount > 0) { // will always be true, due to semantics of blockForAvailableThreads...

                            List<OperableTrigger> triggers = null;

                            long now = System.currentTimeMillis();

                            clearSignaledSchedulingChange();
                            try {
                                //1.从jobStore中获取下次要触发的触发器集合//idleWaitTime == 30L * 1000L; 当调度程序发现没有当前触发器要触发,它应该等待多长时间再检查
                                triggers = qsRsrcs.getJobStore().acquireNextTriggers(
                                        now + idleWaitTime, Math.min(availThreadCount, qsRsrcs.getMaxBatchSize()), qsRsrcs.getBatchTimeWindow());
                                lastAcquireFailed = false;
                                if (log.isDebugEnabled()) 
                                    log.debug("batch acquisition of " + (triggers == null ? 0 : triggers.size()) + " triggers");
                            } catch (JobPersistenceException jpe) {
                                if(!lastAcquireFailed) {
                                    qs.notifySchedulerListenersError(
                                        "An error occurred while scanning for the next triggers to fire.",
                                        jpe);
                                }
                                lastAcquireFailed = true;
                                continue;
                            } catch (RuntimeException e) {
                                if(!lastAcquireFailed) {
                                    getLog().error("quartzSchedulerThreadLoop: RuntimeException "
                                            +e.getMessage(), e);
                                }
                                lastAcquireFailed = true;
                                continue;
                            }
                            //若查询出触发器,则进行触发
                            if (triggers != null && !triggers.isEmpty()) {

                                now = System.currentTimeMillis();
                                long triggerTime = triggers.get(0).getNextFireTime().getTime();
                                long timeUntilTrigger = triggerTime - now;
                                //循环直至距离触发时间前2毫秒
                                while(timeUntilTrigger > 2) {
                                    synchronized (sigLock) {
                                        if (halted.get()) {
                                            break;
                                        }
                                        if (!isCandidateNewTimeEarlierWithinReason(triggerTime, false)) {
                                            try {
                                                // we could have blocked a long while
                                                // on 'synchronize', so we must recompute
                                                now = System.currentTimeMillis();
                                                timeUntilTrigger = triggerTime - now;
                                                if(timeUntilTrigger >= 1)
                                                    sigLock.wait(timeUntilTrigger);
                                            } catch (InterruptedException ignore) {
                                            }
                                        }
                                    }
                                    if(releaseIfScheduleChangedSignificantly(triggers, triggerTime)) {
                                        break;
                                    }
                                    now = System.currentTimeMillis();
                                    timeUntilTrigger = triggerTime - now;
                                }

                                // this happens if releaseIfScheduleChangedSignificantly decided to release triggers
                                if(triggers.isEmpty())
                                    continue;

                                // set triggers to 'executing'
                                List<TriggerFiredResult> bndles = new ArrayList<TriggerFiredResult>();

                                boolean goAhead = true;
                                synchronized(sigLock) {
                                    goAhead = !halted.get();
                                }
                                if(goAhead) {
                                    try {
                                        //2.通知JobStore触发,其中加锁,更改状态
                                        List<TriggerFiredResult> res = qsRsrcs.getJobStore().triggersFired(triggers);
                                        if(res != null)
                                            //返回的数据赋值到bndles
                                            bndles = res;
                                    } catch (SchedulerException se) {
                                        qs.notifySchedulerListenersError(
                                                "An error occurred while firing triggers '"
                                                        + triggers + "'", se);
                                        //QTZ-179 : a problem occurred interacting with the triggers from the db
                                        //we release them and loop again
                                        for (int i = 0; i < triggers.size(); i++) {
                                            //异常时,下同 数据库中ACQUIRED状态更新回WAITING后下次循环
                                            qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));
                                        }
                                        continue;
                                    }

                                }
                                //数据库关于quartz的表全部设置完成
                                for (int i = 0; i < bndles.size(); i++) {
                                    TriggerFiredResult result =  bndles.get(i);
                                    TriggerFiredBundle bndle =  result.getTriggerFiredBundle();
                                    Exception exception = result.getException();

                                    if (exception instanceof RuntimeException) {
                                        getLog().error("RuntimeException while firing trigger " + triggers.get(i), exception);
                                        
                                        qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));
                                        continue;
                                    }

                                    // it's possible to get 'null' if the triggers was paused,
                                    // blocked, or other similar occurrences that prevent it being
                                    // fired at this time...  or if the scheduler was shutdown (halted)
                                    if (bndle == null) {
                                        
                                        qsRsrcs.getJobStore().releaseAcquiredTrigger(triggers.get(i));
                                        continue;
                                    }

                                    JobRunShell shell = null;
                                    try {
                                        //3.创建JobRunShell并初始化
                                        shell = qsRsrcs.getJobRunShellFactory().createJobRunShell(bndle);
                                        shell.initialize(qs);
                                    } catch (SchedulerException se) {
                                        qsRsrcs.getJobStore().triggeredJobComplete(triggers.get(i), bndle.getJobDetail(), CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR);
                                        continue;
                                    }
                                    //交由线程池处理任务
                                    if (qsRsrcs.getThreadPool().runInThread(shell) == false) {
                                        // this case should never happen, as it is indicative of the
                                        // scheduler being shutdown or a bug in the thread pool or
                                        // a thread pool being used concurrently - which the docs
                                        // say not to do...调度程序正在关闭或线程池或线程池中并发使用的错误
                                        getLog().error("ThreadPool.runInThread() return false!");
                                        qsRsrcs.getJobStore().triggeredJobComplete(triggers.get(i), bndle.getJobDetail(), CompletedExecutionInstruction.SET_ALL_JOB_TRIGGERS_ERROR);
                                    }

                                }

                                continue; // while (!halted)
                            }
                        } else { // if(availThreadCount > 0)
                            // should never happen, if threadPool.blockForAvailableThreads() follows contract
                            continue; // while (!halted)
                        }
                        //在最后调度线程生成了一个随机的等待时间,进入短暂的等待,这使得其他节点的调度器都有机会获取数据库资源.如此就实现了quratz的负载平衡
                        long now = System.currentTimeMillis();
                        long waitTime = now + getRandomizedIdleWaitTime();
                        long timeUntilContinue = waitTime - now;
                        synchronized(sigLock) {
                            try {
                              if(!halted.get()) {
                                // QTZ-336 A job might have been completed in the mean time and we might have
                                // missed the scheduled changed signal by not waiting for the notify() yet
                                // Check that before waiting for too long in case this very job needs to be
                                // scheduled very soon
                                if (!isScheduleChanged()) {
                                  sigLock.wait(timeUntilContinue);
                                }
                              }
                            } catch (InterruptedException ignore) {
                            }
                        }

                    } catch(RuntimeException re) {
                        getLog().error("Runtime error occurred in main trigger firing loop.", re);
                    }
                } // while (!halted)

                // drop references to scheduler stuff to aid garbage collection...
                qs = null;
                qsRsrcs = null;
            }
2.2.1.获取下次要触发的触发器集合

过程为:获取待触发trigger-->数据库LOCKS表TRIGGER_ACCESS行加锁-->读取JobDetail信息-->读取trigger表中触发器信息并标记为"已获取"-->commit事务,释放锁

public List<OperableTrigger> acquireNextTriggers(final long noLaterThan, final int maxCount, final long timeWindow)
                throws JobPersistenceException {
                
                String lockName;
                //isAcquireTriggersWithinLock()方法判断属性acquireTriggersWithinLock默认为false,maxCount默认=1故默认不加锁
                //可以在配置文件中配置org.quartz.jobStore.acquireTriggersWithinLock=true使其每次获取时加锁
                if(isAcquireTriggersWithinLock() || maxCount > 1) { 
                    lockName = LOCK_TRIGGER_ACCESS;
                } else {
                    lockName = null;
                }
                return executeInNonManagedTXLock(lockName, 
                        new TransactionCallback<List<OperableTrigger>>() {
                            public List<OperableTrigger> execute(Connection conn) throws JobPersistenceException {
                                //返回下次需要执行的trigger
                                return acquireNextTrigger(conn, noLaterThan, maxCount, timeWindow);
                            }
                        },
                        new TransactionValidator<List<OperableTrigger>>() {
                            public Boolean validate(Connection conn, List<OperableTrigger> result) throws JobPersistenceException {
                                try {
                                    List<FiredTriggerRecord> acquired = getDelegate().selectInstancesFiredTriggerRecords(conn, getInstanceId());
                                    Set<String> fireInstanceIds = new HashSet<String>();
                                    for (FiredTriggerRecord ft : acquired) {
                                        fireInstanceIds.add(ft.getFireInstanceId());
                                    }
                                    for (OperableTrigger tr : result) {
                                        if (fireInstanceIds.contains(tr.getFireInstanceId())) {
                                            return true;
                                        }
                                    }
                                    return false;
                                } catch (SQLException e) {
                                    throw new JobPersistenceException("error validating trigger acquisition", e);
                                }
                            }
                        });
            }
protected List<OperableTrigger> acquireNextTrigger(Connection conn, long noLaterThan, int maxCount, long timeWindow)
                throws JobPersistenceException {
                if (timeWindow < 0) {
                  throw new IllegalArgumentException();
                }
                
                List<OperableTrigger> acquiredTriggers = new ArrayList<OperableTrigger>();
                Set<JobKey> acquiredJobKeysForNoConcurrentExec = new HashSet<JobKey>();
                final int MAX_DO_LOOP_RETRY = 3;
                int currentLoopCount = 0;
                do {
                    currentLoopCount ++;
                    try {
                        //sql为:SELECT TRIGGER_NAME, TRIGGER_GROUP, NEXT_FIRE_TIME, PRIORITY FROM {0}TRIGGERS 
                        //WHERE SCHED_NAME = {1} AND TRIGGER_STATE = ? AND NEXT_FIRE_TIME <= ? AND (MISFIRE_INSTR = -1 OR (MISFIRE_INSTR != -1 AND NEXT_FIRE_TIME >= ?)) ORDER BY NEXT_FIRE_TIME ASC, PRIORITY DESC
                        List<TriggerKey> keys = getDelegate().selectTriggerToAcquire(conn, noLaterThan + timeWindow, getMisfireTime(), maxCount);
                        
                        // No trigger is ready to fire yet.
                        if (keys == null || keys.size() == 0)
                            return acquiredTriggers;

                        long batchEnd = noLaterThan;

                        for(TriggerKey triggerKey: keys) {
                            // If our trigger is no longer available, try a new one.
                            //sql:SELECT * FROM {0}TRIGGERS WHERE SCHED_NAME = {1} AND TRIGGER_NAME = ? AND TRIGGER_GROUP = ?
                            OperableTrigger nextTrigger = retrieveTrigger(conn, triggerKey);
                            if(nextTrigger == null) {
                                continue; // next trigger
                            }
                            
                            // If trigger's job is set as @DisallowConcurrentExecution, and it has already been added to result, then
                            // put it back into the timeTriggers set and continue to search for next trigger.
                            
                            JobKey jobKey = nextTrigger.getJobKey();
                            JobDetail job;
                            try {
                                //sql:SELECT * FROM {0}JOB_DETAILS WHERE SCHED_NAME = {1} AND JOB_NAME = ? AND JOB_GROUP = ?
                                job = retrieveJob(conn, jobKey);
                            } catch (JobPersistenceException jpe) {
                                try {
                                    getLog().error("Error retrieving job, setting trigger state to ERROR.", jpe);
                                    getDelegate().updateTriggerState(conn, triggerKey, STATE_ERROR);
                                } catch (SQLException sqle) {
                                    getLog().error("Unable to set trigger state to ERROR.", sqle);
                                }
                                continue;
                            }
                            //(有状态任务,类上是否加上注解@DisallowConcurrentExecution或实现StatefulJob,任务执行时间过长,下一次任务时间开始则阻塞不触发)
                            if (job.isConcurrentExectionDisallowed()) {
                                //若已经存在则跳过
                                if (acquiredJobKeysForNoConcurrentExec.contains(jobKey)) {
                                    continue; // next trigger
                                } else {
                                    acquiredJobKeysForNoConcurrentExec.add(jobKey);
                                }
                            }
                            
                            if (nextTrigger.getNextFireTime().getTime() > batchEnd) {
                              break;
                            }
                            // We now have a acquired trigger, let's add to return list.
                            // If our trigger was no longer in the expected state, try a new one.
                            //将查询出的WAITING状态的trigger更新为ACQUIRED
                            //sql:UPDATE {0}TRIGGERS SET TRIGGER_STATE = ? WHERE SCHED_NAME = {1} AND TRIGGER_NAME = ? AND TRIGGER_GROUP = ? AND TRIGGER_STATE = ?
                            int rowsUpdated = getDelegate().updateTriggerStateFromOtherState(conn, triggerKey, STATE_ACQUIRED, STATE_WAITING);
                            if (rowsUpdated <= 0) {
                                continue; // next trigger
                            }
                            nextTrigger.setFireInstanceId(getFiredTriggerRecordId());
                            //sql:INSERT INTO {0}FIRED_TRIGGERS (SCHED_NAME, ENTRY_ID, TRIGGER_NAME, TRIGGER_GROUP, INSTANCE_NAME, FIRED_TIME, SCHED_TIME, STATE, JOB_NAME, JOB_GROUP, IS_NONCONCURRENT, REQUESTS_RECOVERY, PRIORITY) 
                            //VALUES({1}, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
                        
                            getDelegate().insertFiredTrigger(conn, nextTrigger, STATE_ACQUIRED, null);

                            if(acquiredTriggers.isEmpty()) {
                                batchEnd = Math.max(nextTrigger.getNextFireTime().getTime(), System.currentTimeMillis()) + timeWindow;
                            }
                            //下次执行的Trigger放入acquiredTriggers List中 
                            acquiredTriggers.add(nextTrigger);
                        }

                        // if we didn't end up with any trigger to fire from that first
                        // batch, try again for another batch. We allow with a max retry count.
                        //如果为空,可以循环3次
                        if(acquiredTriggers.size() == 0 && currentLoopCount < MAX_DO_LOOP_RETRY) {
                            continue;
                        }
                        
                        // We are done with the while loop.
                        break;
                    } catch (Exception e) {
                        throw new JobPersistenceException(
                                  "Couldn't acquire next trigger: " + e.getMessage(), e);
                    }
                } while (true);
                
                // Return the acquired trigger list
                return acquiredTriggers;
            }
2.2.2.触发trigger

执行过程与上述过程类似,此时是必定加锁的:数据库LOCKS表STATE_ACCESS行加锁-->确认trigger的状态-->读取trigger的JobDetail信息-->读取trigger的Calendar信息-->更新trigger信息-->commit事务,释放锁

public List<TriggerFiredResult> triggersFired(final List<OperableTrigger> triggers) throws JobPersistenceException {
                return executeInNonManagedTXLock(LOCK_TRIGGER_ACCESS,
                        new TransactionCallback<List<TriggerFiredResult>>() {
                            public List<TriggerFiredResult> execute(Connection conn) throws JobPersistenceException {
                                List<TriggerFiredResult> results = new ArrayList<TriggerFiredResult>();

                                TriggerFiredResult result;
                                for (OperableTrigger trigger : triggers) {
                                    try {
                                        //主要方法
                                      TriggerFiredBundle bundle = triggerFired(conn, trigger);
                                      result = new TriggerFiredResult(bundle);
                                    } catch (JobPersistenceException jpe) {
                                        result = new TriggerFiredResult(jpe);
                                    } catch(RuntimeException re) {
                                        result = new TriggerFiredResult(re);
                                    }
                                    results.add(result);
                                }

                                return results;
                            }
                        },
                        new TransactionValidator<List<TriggerFiredResult>>() {
                            @Override
                            public Boolean validate(Connection conn, List<TriggerFiredResult> result) throws JobPersistenceException {
                                try {
                                    List<FiredTriggerRecord> acquired = getDelegate().selectInstancesFiredTriggerRecords(conn, getInstanceId());
                                    Set<String> executingTriggers = new HashSet<String>();
                                    for (FiredTriggerRecord ft : acquired) {
                                        if (STATE_EXECUTING.equals(ft.getFireInstanceState())) {
                                            executingTriggers.add(ft.getFireInstanceId());
                                        }
                                    }
                                    for (TriggerFiredResult tr : result) {
                                        if (tr.getTriggerFiredBundle() != null && executingTriggers.contains(tr.getTriggerFiredBundle().getTrigger().getFireInstanceId())) {
                                            return true;
                                        }
                                    }
                                    return false;
                                } catch (SQLException e) {
                                    throw new JobPersistenceException("error validating trigger acquisition", e);
                                }
                            }
                        });
            }
protected TriggerFiredBundle triggerFired(Connection conn,
            OperableTrigger trigger)
                throws JobPersistenceException {
                JobDetail job;
                Calendar cal = null;

                // Make sure trigger wasn't deleted, paused, or completed...
                try { // if trigger was deleted, state will be STATE_DELETED
                    //查询状态,不为触发状态则跳过
                    //sql:SELECT TRIGGER_STATE FROM {0}TRIGGERS WHERE SCHED_NAME = {1} AND TRIGGER_NAME = ? AND TRIGGER_GROUP = ?
                    String state = getDelegate().selectTriggerState(conn,
                            trigger.getKey());
                    if (!state.equals(STATE_ACQUIRED)) {
                        return null;
                    }
                } catch (SQLException e) {
                    throw new JobPersistenceException("Couldn't select trigger state: "
                            + e.getMessage(), e);
                }

                try {
                    //sql:SELECT * FROM {0}JOB_DETAILS WHERE SCHED_NAME = {1} AND JOB_NAME = ? AND JOB_GROUP = ?
                    job = retrieveJob(conn, trigger.getJobKey());
                    if (job == null) { return null; }
                } catch (JobPersistenceException jpe) {
                    try {
                        getLog().error("Error retrieving job, setting trigger state to ERROR.", jpe);
                        getDelegate().updateTriggerState(conn, trigger.getKey(),
                                STATE_ERROR);
                    } catch (SQLException sqle) {
                        getLog().error("Unable to set trigger state to ERROR.", sqle);
                    }
                    throw jpe;
                }
                //若有设置特殊的日期与cron关联
                if (trigger.getCalendarName() != null) {
                    cal = retrieveCalendar(conn, trigger.getCalendarName());
                    if (cal == null) { return null; }
                }

                try {
                    //更新执行中trigger的信息
                    //sql:UPDATE {0}FIRED_TRIGGERS SET INSTANCE_NAME = ?, FIRED_TIME = ?, SCHED_TIME = ?, STATE = ?, JOB_NAME = ?, JOB_GROUP = ?, IS_NONCONCURRENT = ?, REQUESTS_RECOVERY = ? WHERE SCHED_NAME = {1} AND ENTRY_ID = ?
                    getDelegate().updateFiredTrigger(conn, trigger, STATE_EXECUTING, job);
                } catch (SQLException e) {
                    throw new JobPersistenceException("Couldn't insert fired trigger: "
                            + e.getMessage(), e);
                }

                Date prevFireTime = trigger.getPreviousFireTime();

                // call triggered - to update the trigger's next-fire-time state...
                //更新触发器的下一个触发时间状态
                //previousFireTime = nextFireTime;
                //nextFireTime = getFireTimeAfter(nextFireTime);
                trigger.triggered(cal);

                String state = STATE_WAITING;
                boolean force = true;
                //任务是否是有状态的,若是,则将状态STATE_WAITING-->STATE_BLOCKED,STATE_ACQUIRED-->STATE_BLOCKED,STATE_PAUSED-->STATE_PAUSED_BLOCKED
                if (job.isConcurrentExectionDisallowed()) {
                    state = STATE_BLOCKED;
                    force = false;
                    try {
                        getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(),
                                STATE_BLOCKED, STATE_WAITING);
                        getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(),
                                STATE_BLOCKED, STATE_ACQUIRED);
                        getDelegate().updateTriggerStatesForJobFromOtherState(conn, job.getKey(),
                                STATE_PAUSED_BLOCKED, STATE_PAUSED);
                    } catch (SQLException e) {
                        throw new JobPersistenceException(
                                "Couldn't update states of blocked triggers: "
                                        + e.getMessage(), e);
                    }
                } 
                //判断是否还有下次触发
                if (trigger.getNextFireTime() == null) {
                    state = STATE_COMPLETE;
                    force = true;
                }
                //插入或更新trigger
                storeTrigger(conn, trigger, job, true, state, force, false);

                job.getJobDataMap().clearDirtyFlag();
                //创建一个 TriggerFiredBundle的对象
                return new TriggerFiredBundle(job, trigger, cal, trigger.getKey().getGroup()
                        .equals(Scheduler.DEFAULT_RECOVERY_GROUP), new Date(), trigger
                        .getPreviousFireTime(), prevFireTime, trigger.getNextFireTime());
            }
2.2.3.实例化并执行Job

为每个Job生成一个可运行的RunShell,并放入线程池运行

public boolean runInThread(Runnable runnable) {
                if (runnable == null) {
                    return false;
                }

                synchronized (nextRunnableLock) {

                    handoffPending = true;

                    // Wait until a worker thread is available
                    //直至线程池有可用线程
                    while ((availWorkers.size() < 1) && !isShutdown) {
                        try {
                            nextRunnableLock.wait(500);
                        } catch (InterruptedException ignore) {
                        }
                    }

                    if (!isShutdown) {
                        WorkerThread wt = (WorkerThread)availWorkers.removeFirst();
                        busyWorkers.add(wt);
                        wt.run(runnable);
                    } else {
                        // If the thread pool is going down, execute the Runnable
                        // within a new additional worker thread (no thread from the pool).
                        WorkerThread wt = new WorkerThread(this, threadGroup,
                                "WorkerThread-LastJob", prio, isMakeThreadsDaemons(), runnable);
                        busyWorkers.add(wt);
                        workers.add(wt);
                        wt.start();
                    }
                    nextRunnableLock.notifyAll();
                    handoffPending = false;
                }

                return true;
            }
public void run() {
                qs.addInternalSchedulerListener(this);

                try {
                    OperableTrigger trigger = (OperableTrigger) jec.getTrigger();
                    JobDetail jobDetail = jec.getJobDetail();

                    do {

                        JobExecutionException jobExEx = null;
                        Job job = jec.getJobInstance();

                        try {
                            begin();
                        } catch (SchedulerException se) {
                            qs.notifySchedulerListenersError("Error executing Job ("
                                    + jec.getJobDetail().getKey()
                                    + ": couldn't begin execution.", se);
                            break;
                        }

                        // notify job & trigger listeners...
                        try {
                            if (!notifyListenersBeginning(jec)) {
                                break;
                            }
                        } catch(VetoedException ve) {
                            try {
                                CompletedExecutionInstruction instCode = trigger.executionComplete(jec, null);
                                qs.notifyJobStoreJobVetoed(trigger, jobDetail, instCode);
                                
                                // QTZ-205
                                // Even if trigger got vetoed, we still needs to check to see if it's the trigger's finalized run or not.
                                if (jec.getTrigger().getNextFireTime() == null) {
                                    qs.notifySchedulerListenersFinalized(jec.getTrigger());
                                }

                                complete(true);
                            } catch (SchedulerException se) {
                                qs.notifySchedulerListenersError("Error during veto of Job ("
                                        + jec.getJobDetail().getKey()
                                        + ": couldn't finalize execution.", se);
                            }
                            break;
                        }

                        long startTime = System.currentTimeMillis();
                        long endTime = startTime;

                        // execute the job
                        try {
                            log.debug("Calling execute on job " + jobDetail.getKey());
                            //执行JOB的execute(),在测试中为QuartzJobBean的execute()其中会调用子类的executeInternal()方法
                            job.execute(jec);
                            endTime = System.currentTimeMillis();
                        } catch (JobExecutionException jee) {
                            //如果execute抛出异常,并且是JobExecutionException,JobExecutionException会保存着是重试,还是结束的信息
                            endTime = System.currentTimeMillis();
                            jobExEx = jee;
                            getLog().info("Job " + jobDetail.getKey() +
                                    " threw a JobExecutionException: ", jobExEx);
                        } catch (Throwable e) {
                            endTime = System.currentTimeMillis();
                            getLog().error("Job " + jobDetail.getKey() +
                                    " threw an unhandled Exception: ", e);
                            SchedulerException se = new SchedulerException(
                                    "Job threw an unhandled exception.", e);
                            qs.notifySchedulerListenersError("Job ("
                                    + jec.getJobDetail().getKey()
                                    + " threw an exception.", se);
                            jobExEx = new JobExecutionException(se, false);
                        }

                        jec.setJobRunTime(endTime - startTime);

                        // notify all job listeners
                        if (!notifyJobListenersComplete(jec, jobExEx)) {
                            break;
                        }

                        CompletedExecutionInstruction instCode = CompletedExecutionInstruction.NOOP;

                        // update the trigger
                        try {
                            //根据不同状态设置不同指令编码
                            instCode = trigger.executionComplete(jec, jobExEx);
                        } catch (Exception e) {
                            // If this happens, there's a bug in the trigger...
                            SchedulerException se = new SchedulerException(
                                    "Trigger threw an unhandled exception.", e);
                            qs.notifySchedulerListenersError(
                                    "Please report this error to the Quartz developers.",
                                    se);
                        }

                        // notify all trigger listeners
                        if (!notifyTriggerListenersComplete(jec, instCode)) {
                            break;
                        }

                        // update job/trigger or re-execute job
                        if (instCode == CompletedExecutionInstruction.RE_EXECUTE_JOB) {
                            jec.incrementRefireCount();
                            try {
                                complete(false);
                            } catch (SchedulerException se) {
                                qs.notifySchedulerListenersError("Error executing Job ("
                                        + jec.getJobDetail().getKey()
                                        + ": couldn't finalize execution.", se);
                            }
                            continue;
                        }

                        try {
                            complete(true);
                        } catch (SchedulerException se) {
                            qs.notifySchedulerListenersError("Error executing Job ("
                                    + jec.getJobDetail().getKey()
                                    + ": couldn't finalize execution.", se);
                            continue;
                        }
                        //任务完成,其方法中 根据instCode的值去更新不同的状态,若加入了注解@DisallowConcurrentExecution则将STATE_BLOCKED-->STATE_BLOCKED
                        //若加上@PersistJobDataAfterExecution,则将_job_details表中的jobMapData数据持久化用于下次执行共享
                        qs.notifyJobStoreJobComplete(trigger, jobDetail, instCode);
                        break;
                    } while (true);

                } finally {
                    qs.removeInternalSchedulerListener(this);
                }
            }

猜你喜欢

转载自www.cnblogs.com/lantuanqing/p/10998079.html