美文网首页征服Spring程序员Java学习笔记
定时任务管理系统(Quartz和Spring的整合)开源和源码简

定时任务管理系统(Quartz和Spring的整合)开源和源码简

作者: holly_wang_王小飞 | 来源:发表于2017-03-07 22:24 被阅读501次

利用学习的时间这里写了个Spring和Quartz结合的一个web项目,纯后端的项目,restful接口
实现对定时任务的增、删、改、查、停止, 启动、定时规则修改、立即执行等。github地址,这里刚开始是为了学习源码,后来有了一些改动,再后来就想做一些业务上的改造,所以clone了一个quartz-core的项目进行改造,后期打算对其集群方式进行改造等等。github地址,有一起感兴趣的朋友可以一起改造,目前的项目比较简单可以作为学习入门的项目,也可以作为搭建job管理系统的初期项目,慢慢迭代。

今天简单说一下SchedulerFactoryBean的初始化过程。
  我们知道bean在初始化的时候会对属性进行set赋值的方法 配置的属性中有

<property name="dataSource" ref="druidDataSource" />
        <property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
        <property name="schedulerName" value="QuartzScheduler" />
        <property name="quartzProperties">
            <props>
                <prop key="org.quartz.scheduler.instanceName">Taskscheduler</prop>
                <prop key="org.quartz.scheduler.instanceId">AUTO</prop>
                <!--线程池配置 -->
                <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
                <prop key="org.quartz.threadPool.threadCount">20</prop>
                <prop key="org.quartz.threadPool.threadPriority">5</prop>
                <!--JobStore 配置 -->
                <prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
                <!-- 集群配置 -->
                <prop key="org.quartz.jobStore.isClustered">true</prop>
                <prop key="org.quartz.jobStore.clusterCheckinInterval">15000</prop>
                <prop key="org.quartz.jobStore.maxMisfiresToHandleAtATime">1</prop>
                <prop key="org.quartz.jobStore.misfireThreshold">120000</prop>
                <prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
            </props>
        </property>

因为实现了InitializingBean接口所以在属性set赋值完以后会调用afterPropertiesSet方法,整个和Quartz的结合的关键就在这里

@Override
    public void afterPropertiesSet() throws Exception {
        if (this.dataSource == null && this.nonTransactionalDataSource != null) {
            this.dataSource = this.nonTransactionalDataSource;
        }

        if (this.applicationContext != null && this.resourceLoader == null) {
            this.resourceLoader = this.applicationContext;
        }

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

        if (this.resourceLoader != null) {
            // Make given ResourceLoader available for SchedulerFactory configuration.
            configTimeResourceLoaderHolder.set(this.resourceLoader);
        }
        if (this.taskExecutor != null) {
            // Make given TaskExecutor available for SchedulerFactory configuration.
            configTimeTaskExecutorHolder.set(this.taskExecutor);
        }
        if (this.dataSource != null) {
            // Make given DataSource available for SchedulerFactory configuration.
            configTimeDataSourceHolder.set(this.dataSource);
        }
        if (this.nonTransactionalDataSource != null) {
            // Make given non-transactional DataSource available for SchedulerFactory configuration.
            configTimeNonTransactionalDataSourceHolder.set(this.nonTransactionalDataSource);
        }

        // 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);
            }
        }

        finally {
            if (this.resourceLoader != null) {
                configTimeResourceLoaderHolder.remove();
            }
            if (this.taskExecutor != null) {
                configTimeTaskExecutorHolder.remove();
            }
            if (this.dataSource != null) {
                configTimeDataSourceHolder.remove();
            }
            if (this.nonTransactionalDataSource != null) {
                configTimeNonTransactionalDataSourceHolder.remove();
            }
        }

        registerListeners();
        registerJobsAndTriggers();
    }

其中利用了spring的BeanUtils先初始化了工厂类SchedulerFactory,然后调用initSchedulerFactory方法进行了Properties的加载和解析
接着进行scheduler 的创建

this.scheduler = createScheduler(schedulerFactory, this.schedulerName);

到这里其实就和spring没多大关系了,就是相当于调用quzrtz的代码进行创建

    protected Scheduler createScheduler(SchedulerFactory schedulerFactory, String schedulerName)
            throws SchedulerException {

        // Override thread context ClassLoader to work around naive Quartz ClassLoadHelper loading.
        Thread currentThread = Thread.currentThread();
        ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
        boolean overrideClassLoader = (this.resourceLoader != null &&
                !this.resourceLoader.getClassLoader().equals(threadContextClassLoader));
        if (overrideClassLoader) {
            currentThread.setContextClassLoader(this.resourceLoader.getClassLoader());
        }
        try {
            SchedulerRepository repository = SchedulerRepository.getInstance();
            synchronized (repository) {
                Scheduler existingScheduler = (schedulerName != null ? repository.lookup(schedulerName) : null);
                Scheduler newScheduler = schedulerFactory.getScheduler();
                if (newScheduler == existingScheduler) {
                    throw new IllegalStateException("Active Scheduler of name '" + schedulerName + "' already registered " +
                            "in Quartz SchedulerRepository. Cannot create a new Spring-managed Scheduler of the same name!");
                }
                if (!this.exposeSchedulerInRepository) {
                    // Need to remove it in this case, since Quartz shares the Scheduler instance by default!
                    SchedulerRepository.getInstance().remove(newScheduler.getSchedulerName());
                }
                return newScheduler;
            }
        }
        finally {
            if (overrideClassLoader) {
                // Reset original thread context ClassLoader.
                currentThread.setContextClassLoader(threadContextClassLoader);
            }
        }
    }

这里有SchedulerRepository这个类来存放scheduler,会判断是否已经创建过相同的scheduler,如果已经创建了 会抛出异常
接着是一个比较有趣的方法populateSchedulerContext();

private void populateSchedulerContext() throws SchedulerException {
        // Put specified objects into Scheduler context.
        if (this.schedulerContextMap != null) {
            this.scheduler.getContext().putAll(this.schedulerContextMap);
        }

        // Register ApplicationContext in Scheduler context.
        if (this.applicationContextSchedulerContextKey != null) {
            if (this.applicationContext == null) {
                throw new IllegalStateException(
                    "SchedulerFactoryBean needs to be set up in an ApplicationContext " +
                    "to be able to handle an 'applicationContextSchedulerContextKey'");
            }
            this.scheduler.getContext().put(this.applicationContextSchedulerContextKey, this.applicationContext);
        }
    }

是吧applicationContext放到了quartz执行的上下文中,这样以后要用到的时候就方便了。
接着是registerListeners();方法,quartz中分为全局的listener和对应schedulerListeners,注册成功后有事件会进行调用通知,算是一种观察者模式吧

protected void registerListeners() throws SchedulerException {
        ListenerManager listenerManager = getScheduler().getListenerManager();
        if (this.schedulerListeners != null) {
            for (SchedulerListener listener : this.schedulerListeners) {
                listenerManager.addSchedulerListener(listener);
            }
        }
        if (this.globalJobListeners != null) {
            for (JobListener listener : this.globalJobListeners) {
                listenerManager.addJobListener(listener);
            }
        }
        if (this.globalTriggerListeners != null) {
            for (TriggerListener listener : this.globalTriggerListeners) {
                listenerManager.addTriggerListener(listener);
            }
        }
    }

接着到了registerJobsAndTriggers方法

protected void registerJobsAndTriggers() throws SchedulerException {
        TransactionStatus transactionStatus = null;
        if (this.transactionManager != null) {
            transactionStatus = this.transactionManager.getTransaction(new DefaultTransactionDefinition());
        }

        try {
            if (this.jobSchedulingDataLocations != null) {
                ClassLoadHelper clh = new ResourceLoaderClassLoadHelper(this.resourceLoader);
                clh.initialize();
                XMLSchedulingDataProcessor dataProcessor = new XMLSchedulingDataProcessor(clh);
                for (String location : this.jobSchedulingDataLocations) {
                    dataProcessor.processFileAndScheduleJobs(location, getScheduler());
                }
            }

            // Register JobDetails.
            if (this.jobDetails != null) {
                for (JobDetail jobDetail : this.jobDetails) {
                    addJobToScheduler(jobDetail);
                }
            }
            else {
                // Create empty list for easier checks when registering triggers.
                this.jobDetails = new LinkedList<JobDetail>();
            }

            // Register Calendars.
            if (this.calendars != null) {
                for (String calendarName : this.calendars.keySet()) {
                    Calendar calendar = this.calendars.get(calendarName);
                    getScheduler().addCalendar(calendarName, calendar, true, true);
                }
            }

            // Register Triggers.
            if (this.triggers != null) {
                for (Trigger trigger : this.triggers) {
                    addTriggerToScheduler(trigger);
                }
            }
        }

        catch (Throwable ex) {
            if (transactionStatus != null) {
                try {
                    this.transactionManager.rollback(transactionStatus);
                }
                catch (TransactionException tex) {
                    logger.error("Job registration exception overridden by rollback exception", ex);
                    throw tex;
                }
            }
            if (ex instanceof SchedulerException) {
                throw (SchedulerException) ex;
            }
            if (ex instanceof Exception) {
                throw new SchedulerException("Registration of jobs and triggers failed: " + ex.getMessage(), ex);
            }
            throw new SchedulerException("Registration of jobs and triggers failed: " + ex.getMessage());
        }

        if (transactionStatus != null) {
            this.transactionManager.commit(transactionStatus);
        }
    }

进行job calendar triggers 的register。
初始化完成!

相关文章

网友评论

    本文标题:定时任务管理系统(Quartz和Spring的整合)开源和源码简

    本文链接:https://www.haomeiwen.com/subject/mxdvgttx.html