初識Quartz之Scheduler組件

        之前在Trigger組件中的withSchedule(ScheduleBuilder scheduleBuilder)方法中,接觸過ScheduleBuilder抽象類,通過將ScheduleBuilder對象傳入用於調度參數的設置。本文主要講述的是Scheduler組件,Scheduler組件主要用於將前文講述的Job組件中的JobDetail對象和Trigger對象綁定在一起,進行完整的調度運行。

1.SchedulerFactory

        之前JobDetail和Trigger創建對象都是使用對應的Builder類進行創建的,而Scheduler對象則稍有不同,而是使用工廠類進行創建。首先創建一個工廠類對象,即SchedulerFactory對象,其中SchedulerFactory是一個接口,裏面有三個關於創建Scheduler對象的方法。

public interface SchedulerFactory {

    /*
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     * 
     * Interface.
     * 
     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     */

    /**
     * <p>
     * Returns a client-usable handle to a <code>Scheduler</code>.
     * </p>
     * 
     * @throws SchedulerException
     *           if there is a problem with the underlying <code>Scheduler</code>.
     */
    Scheduler getScheduler() throws SchedulerException;

    /**
     * <p>
     * Returns a handle to the Scheduler with the given name, if it exists.
     * </p>
     */
    Scheduler getScheduler(String schedName) throws SchedulerException;

    /**
     * <p>
     * Returns handles to all known Schedulers (made by any SchedulerFactory
     * within this jvm.).
     * </p>
     */
    Collection<Scheduler> getAllSchedulers() throws SchedulerException;

}

        創建SchedulerFactory對象需要找到SchedulerFactory接口的實現類,本文講述的實現類是StdSchedulerFactory,該類實現了接口的三個方法,因此創建完SchedulerFactory對象後,可以調用相應的方法獲取Scheduler對象,如以下代碼所示:

SchedulerFactory sf=new StdSchedulerFactory();
Scheduler scheduler=sf.getScheduler();

2.啓動與綁定

        Scheduler也是一個接口,它有三個實現類,分別是:StdScheduler、RemoteScheduler、RemoteMBeanScheduler(抽象類,其中JBoss4RMIRemoteMBeanScheduler是抽象類的實現類)。本文以StdScheduler爲例,關於scheduler對象的啓動,StdScheduler有兩個啓動的方法,一個是即時啓動,另一個是延遲啓動。

public void start() throws SchedulerException {
        sched.start();
    }

    /**
     * <p>
     * Calls the equivalent method on the 'proxied' <code>QuartzScheduler</code>.
     * </p>
     */
    public void startDelayed(int seconds) throws SchedulerException {
        sched.startDelayed(seconds);
    }

        其中即時啓動調用了對象名爲sched的start()方法,延遲啓動則是在方法內部調用了對象名爲sched的startDelayed(int seconds)方法,而在StdScheduler類聲明變量時,已經聲明瞭private QuartzScheduler sched;說明sched是QuartzScheduler類型的,可以通過查看QuartzScheduler的源碼,瞭解start()和startDelayed(int seconds)方法。

public void start() throws SchedulerException {

        if (shuttingDown|| closed) {
            throw new SchedulerException(
                    "The Scheduler cannot be restarted after shutdown() has been called.");
        }

        // QTZ-212 : calling new schedulerStarting() method on the listeners
        // right after entering start()
        notifySchedulerListenersStarting();

        if (initialStart == null) {
            initialStart = new Date();
            this.resources.getJobStore().schedulerStarted();            
            startPlugins();
        } else {
            resources.getJobStore().schedulerResumed();
        }

        schedThread.togglePause(false);

        getLog().info(
                "Scheduler " + resources.getUniqueIdentifier() + " started.");
        
        notifySchedulerListenersStarted();
    }

    public void startDelayed(final int seconds) throws SchedulerException
    {
        if (shuttingDown || closed) {
            throw new SchedulerException(
                    "The Scheduler cannot be restarted after shutdown() has been called.");
        }

        Thread t = new Thread(new Runnable() {
            public void run() {
                try { Thread.sleep(seconds * 1000L); }
                catch(InterruptedException ignore) {}
                try { start(); }
                catch(SchedulerException se) {
                    getLog().error("Unable to start secheduler after startup delay.", se);
                }
            }
        });
        t.start();
    }

        其中可以看出start()是即時啓動,而start(int seconds)就是在方法裏定義了一個線程,利用Thread的sleep方法進行等待實現延遲啓動。



       至於綁定,調用scheduler對象的scheduleJob(JobDetail jobDetail, Trigger trigger)方法。

public Date scheduleJob(JobDetail jobDetail, Trigger trigger)
        throws SchedulerException {
        return sched.scheduleJob(jobDetail, trigger);
    }

         以下是QuartzScheduler類的scheduleJob(JobDetail jobDetail, Trigger trigger)方法,該方法對JobDetail對象和Trigger對象進行綁定。並且傳入scheduler對象中。

public Date scheduleJob(JobDetail jobDetail,
            Trigger trigger) throws SchedulerException {
        validateState();

        if (jobDetail == null) {
            throw new SchedulerException("JobDetail cannot be null");
        }
        
        if (trigger == null) {
            throw new SchedulerException("Trigger cannot be null");
        }
        
        if (jobDetail.getKey() == null) {
            throw new SchedulerException("Job's key cannot be null");
        }

        if (jobDetail.getJobClass() == null) {
            throw new SchedulerException("Job's class cannot be null");
        }
        
        OperableTrigger trig = (OperableTrigger)trigger;

        if (trigger.getJobKey() == null) {
            trig.setJobKey(jobDetail.getKey());
        } else if (!trigger.getJobKey().equals(jobDetail.getKey())) {
            throw new SchedulerException(
                "Trigger does not reference given job!");
        }

        trig.validate();

        Calendar cal = null;
        if (trigger.getCalendarName() != null) {
            cal = resources.getJobStore().retrieveCalendar(trigger.getCalendarName());
        }
        Date ft = trig.computeFirstFireTime(cal);

        if (ft == null) {
            throw new SchedulerException(
                    "Based on configured schedule, the given trigger '" + trigger.getKey() + "' will never fire.");
        }

        resources.getJobStore().storeJobAndTrigger(jobDetail, trig);
        notifySchedulerListenersJobAdded(jobDetail);
        notifySchedulerThread(trigger.getNextFireTime().getTime());
        notifySchedulerListenersSchduled(trigger);

        return ft;
    }

         

         以上分析可知,首先創建一個SchedulerFactory對象,通過SchedulerFactory對象的方法構造Scheduler對象,其中Scheduler是一個抽象類,如果使用scheduler對象的start()方法啓動,則需要調用QuartzScheduler類中的start()方法。然後調用QuartzScheduler類中的schduleJob()方法進行trigger和detail的綁定。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章