📄 schedulerfactorybean.java
字号:
/*
* Copyright 2002-2004 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.scheduling.quartz;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Calendar;
import org.quartz.JobDetail;
import org.quartz.JobListener;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SchedulerListener;
import org.quartz.Trigger;
import org.quartz.TriggerListener;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.simpl.SimpleThreadPool;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.NestedRuntimeException;
import org.springframework.core.io.Resource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
/**
* FactoryBean that sets up a Quartz Scheduler and exposes it for bean references.
*
* <p>Allows registration of JobDetails, Calendars and Triggers, automatically
* starting the scheduler on initialization and shutting it down on destruction.
* In scenarios that just require static registration of jobs at startup, there
* is no need to access the Scheduler instance itself in application code.
*
* <p>For dynamic registration of jobs at runtime, use a bean reference to
* this SchedulerFactoryBean to get direct access to the Quartz Scheduler
* (<code>org.quartz.Scheduler</code>). This allows you to create new jobs
* and triggers, and also to control and monitor the entire Scheduler.
*
* <p>Note that Quartz instantiates a new Job for each execution, in
* contrast to Timer which uses a TimerTask instance that is shared
* between repeated executions. Just JobDetail descriptors are shared.
*
* <p>When using persistent jobs, it is strongly recommended to perform all
* operations on the Scheduler within Spring-managed (or plain JTA) transactions.
* Else, database locking will not properly work and might even break.
* (See {@link #setDataSource setDataSource} javadoc for details.)
*
* <p>The preferred way to achieve transactional execution is to demarcate
* declarative transactions at the business facade level, which will
* automatically apply to Scheduler operations performed within those scopes.
* Alternatively, define a TransactionProxyFactoryBean for the Scheduler itself.
*
* <p>SchedulerFactoryBean is fully compatible with both Quartz 1.3
* and 1.4 (through special checks where necessary).
*
* @author Juergen Hoeller
* @since 18.02.2004
* @see #setDataSource
* @see org.quartz.Scheduler
* @see org.quartz.impl.StdSchedulerFactory
* @see org.springframework.transaction.interceptor.TransactionProxyFactoryBean
*/
public class SchedulerFactoryBean
implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
public static final String PROP_THREAD_COUNT = "org.quartz.threadPool.threadCount";
public static final int DEFAULT_THREAD_COUNT = 10;
private static ThreadLocal configTimeDataSourceHolder = new ThreadLocal();
/**
* Return the DataSource for the currently configured Quartz Scheduler,
* to be used by LocalDataSourceJobStore.
* <p>This instance will be set before initialization of the corresponding
* Scheduler, and reset immediately afterwards. It is thus only available
* during configuration.
* @see #setDataSource
* @see LocalDataSourceJobStore
*/
public static DataSource getConfigTimeDataSource() {
return (DataSource) configTimeDataSourceHolder.get();
}
protected final Log logger = LogFactory.getLog(getClass());
private Class schedulerFactoryClass = StdSchedulerFactory.class;
private String schedulerName;
private Resource configLocation;
private Properties quartzProperties;
private DataSource dataSource;
private PlatformTransactionManager transactionManager;
private Map schedulerContextMap;
private ApplicationContext applicationContext;
private String applicationContextSchedulerContextKey;
private boolean overwriteExistingJobs = false;
private String[] jobSchedulingDataLocations;
private List jobDetails;
private Map calendars;
private List triggers;
private SchedulerListener[] schedulerListeners;
private JobListener[] globalJobListeners;
private JobListener[] jobListeners;
private TriggerListener[] globalTriggerListeners;
private TriggerListener[] triggerListeners;
private boolean autoStartup = true;
private int startupDelay = 0;
private boolean waitForJobsToCompleteOnShutdown = false;
private Scheduler scheduler;
/**
* Set the Quartz SchedulerFactory implementation to use.
* <p>Default is StdSchedulerFactory, reading in the standard
* quartz.properties from quartz.jar. To use custom Quartz
* properties, specify "configLocation" or "quartzProperties".
* @see org.quartz.impl.StdSchedulerFactory
* @see #setConfigLocation
* @see #setQuartzProperties
*/
public void setSchedulerFactoryClass(Class schedulerFactoryClass) {
this.schedulerFactoryClass = schedulerFactoryClass;
}
/**
* Set the name of the Scheduler to fetch from the SchedulerFactory.
* If not specified, the default Scheduler will be used.
* @see org.quartz.SchedulerFactory#getScheduler(String)
* @see org.quartz.SchedulerFactory#getScheduler
*/
public void setSchedulerName(String schedulerName) {
this.schedulerName = schedulerName;
}
/**
* Set the location of the Quartz properties config file, for example
* as classpath resource "classpath:quartz.properties".
* <p>Note: Can be omitted when all necessary properties are specified
* locally via this bean, or when relying on Quartz' default configuration.
* @see #setQuartzProperties
*/
public void setConfigLocation(Resource configLocation) {
this.configLocation = configLocation;
}
/**
* Set Quartz properties, like "org.quartz.threadPool.class".
* <p>Can be used to override values in a Quartz properties config file,
* or to specify all necessary properties locally.
* @see #setConfigLocation
*/
public void setQuartzProperties(Properties quartzProperties) {
this.quartzProperties = quartzProperties;
}
/**
* Set the DataSource to be used by the Scheduler. If set,
* this will override corresponding settings in Quartz properties.
* <p>Note: If this is set, the Quartz settings should not define
* a job store "dataSource" to avoid meaningless double configuration.
* <p>A Spring-specific subclass of Quartz' JobStoreCMT will be used.
* It is therefore strongly recommended to perform all operations on
* the Scheduler within Spring-managed (or plain JTA) transactions.
* Else, database locking will not properly work and might even break
* (e.g. if trying to obtain a lock on Oracle without a transaction).
* @see #setQuartzProperties
* @see #setTransactionManager
* @see org.springframework.scheduling.quartz.LocalDataSourceJobStore
*/
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
/**
* Set the transaction manager to be used for registering jobs and triggers
* that are defined by this SchedulerFactoryBean. Default is none; setting
* this only makes sense when specifying a DataSource for the Scheduler.
* @see #setDataSource
*/
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
/**
* Register objects in the Scheduler context via a given Map.
* These objects will be available to any Job that runs in this Scheduler.
* <p>Note: When using persistent Jobs whose JobDetail will be kept in the
* database, do not put Spring-managed beans or an ApplicationContext
* reference into the JobDataMap but rather into the SchedulerContext.
* @param schedulerContextAsMap Map with String keys and any objects as
* values (for example Spring-managed beans)
* @see JobDetailBean#setJobDataAsMap
*/
public void setSchedulerContextAsMap(Map schedulerContextAsMap) {
this.schedulerContextMap = schedulerContextAsMap;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
/**
* Set the key of an ApplicationContext reference to expose in the
* SchedulerContext, for example "applicationContext". Default is none.
* Only applicable when running in a Spring ApplicationContext.
* <p>Note: When using persistent Jobs whose JobDetail will be kept in the
* database, do not put an ApplicationContext reference into the JobDataMap
* but rather into the SchedulerContext.
* <p>In case of a QuartzJobBean, the reference will be applied to the Job
* instance as bean property. An "applicationContext" attribute will
* correspond to a "setApplicationContext" method in that scenario.
* <p>Note that BeanFactory callback interfaces like ApplicationContextAware
* are not automatically applied to Quartz Job instances, because Quartz
* itself is reponsible for the lifecycle of its Jobs.
* @see JobDetailBean#setApplicationContextJobDataKey
* @see org.springframework.context.ApplicationContext
*/
public void setApplicationContextSchedulerContextKey(String applicationContextSchedulerContextKey) {
this.applicationContextSchedulerContextKey = applicationContextSchedulerContextKey;
}
/**
* Set whether any jobs defined on this SchedulerFactoryBean should overwrite
* existing job definitions. Default is "false", to not overwrite already
* registered jobs that have been read in from a persistent job store.
*/
public void setOverwriteExistingJobs(boolean overwriteExistingJobs) {
this.overwriteExistingJobs = overwriteExistingJobs;
}
/**
* Set the location of a Quartz job definition XML file that follows the
* "job_scheduling_data_1_0" DTD. Can be specified to automatically
* register jobs that are defined in such a file, possibly in addition
* to jobs defined directly on this SchedulerFactoryBean.
* @see ResourceJobSchedulingDataProcessor
* @see org.quartz.xml.JobSchedulingDataProcessor
*/
public void setJobSchedulingDataLocation(String jobSchedulingDataLocation) {
this.jobSchedulingDataLocations = new String[] {jobSchedulingDataLocation};
}
/**
* Set the locations of Quartz job definition XML files that follow the
* "job_scheduling_data_1_0" DTD. Can be specified to automatically
* register jobs that are defined in such files, possibly in addition
* to jobs defined directly on this SchedulerFactoryBean.
* @see ResourceJobSchedulingDataProcessor
* @see org.quartz.xml.JobSchedulingDataProcessor
*/
public void setJobSchedulingDataLocations(String[] jobSchedulingDataLocations) {
this.jobSchedulingDataLocations = jobSchedulingDataLocations;
}
/**
* Register a list of JobDetail objects with the Scheduler that
* this FactoryBean creates, to be referenced by Triggers.
* <p>This is not necessary when a Trigger determines the JobDetail
* itself: In this case, the JobDetail will be implicitly registered
* in combination with the Trigger.
* @see #setTriggers
* @see org.quartz.JobDetail
* @see JobDetailBean
* @see JobDetailAwareTrigger
* @see org.quartz.Trigger#setJobName
*/
public void setJobDetails(JobDetail[] jobDetails) {
this.jobDetails = Arrays.asList(jobDetails);
}
/**
* Register a list of Quartz Calendar objects with the Scheduler
* that this FactoryBean creates, to be referenced by Triggers.
* @param calendars Map with calendar names as keys as Calendar
* objects as values
* @see org.quartz.Calendar
* @see org.quartz.Trigger#setCalendarName
*/
public void setCalendars(Map calendars) {
this.calendars = calendars;
}
/**
* Register a list of Trigger objects with the Scheduler that
* this FactoryBean creates.
* <p>If the Trigger determines the corresponding JobDetail itself,
* the job will be automatically registered with the Scheduler.
* Else, the respective JobDetail needs to be registered via the
* "jobDetails" property of this FactoryBean.
* @see #setJobDetails
* @see org.quartz.JobDetail
* @see JobDetailAwareTrigger
* @see CronTriggerBean
* @see SimpleTriggerBean
*/
public void setTriggers(Trigger[] triggers) {
this.triggers = Arrays.asList(triggers);
}
/**
* Specify Quartz SchedulerListeners to be registered with the Scheduler.
*/
public void setSchedulerListeners(SchedulerListener[] schedulerListeners) {
this.schedulerListeners = schedulerListeners;
}
/**
* Specify global Quartz JobListeners to be registered with the Scheduler.
* Such JobListeners will apply to all Jobs in the Scheduler.
*/
public void setGlobalJobListeners(JobListener[] globalJobListeners) {
this.globalJobListeners = globalJobListeners;
}
/**
* Specify named Quartz JobListeners to be registered with the Scheduler.
* Such JobListeners will only apply to Jobs that explicitly activate
* them via their name.
* @see org.quartz.JobListener#getName
* @see org.quartz.JobDetail#addJobListener
* @see JobDetailBean#setJobListenerNames
*/
public void setJobListeners(JobListener[] jobListeners) {
this.jobListeners = jobListeners;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -