美文网首页征服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