Quartz的使用: http://donald-draper.iteye.com/admin/blogs/2321886
Quartz的Job存储,触发器、任务删除,源码分析:
http://donald-draper.iteye.com/admin/blogs/2322725
一般获取Scheduler的方式
第一种:
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler cronScheduler = schedulerFactory.getScheduler();
第二种:
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
下面先来看看第一种到底做了些什么
public class StdSchedulerFactory
implements SchedulerFactory
{
//获取调度器Scheduler
public Scheduler getScheduler()
throws SchedulerException
{
if(cfg == null)
//初始化Quartz属性,线程池,线程数,线程优先级,job存储容器
initialize();
//获取调度器仓库单例
SchedulerRepository schedRep = SchedulerRepository.getInstance();
//根据调度器name,寻到对应的Scheduler
Scheduler sched = schedRep.lookup(getSchedulerName());
if(sched != null)
if(sched.isShutdown())
schedRep.remove(getSchedulerName());
else
return sched;
//初始化调度器
sched = instantiate();
return sched;
}
//从StdSchedulerFactory的getDefaultScheduler方法可以看出
//与getScheduler相同
public static Scheduler getDefaultScheduler()
throws SchedulerException
{
StdSchedulerFactory fact = new StdSchedulerFactory();
return fact.getScheduler();
}
//初始化Quartz属性,线程池,线程数,线程优先级,job存储容器配置
public void initialize()
throws SchedulerException
{
String requestedFile;
String propFileName;
File propFile;
Properties props;
InputStream in;
if(cfg != null)
return;
if(initException != null)
throw initException;
requestedFile = System.getProperty("org.quartz.properties");
propFileName = requestedFile == null ? "quartz.properties" : requestedFile;
propFile = new File(propFileName);
props = new Properties();
in = null;
//如果propFile存在,则从文件系统,加载相应的属性文件
if(propFile.exists())
try
{
if(requestedFile != null)
propSrc = (new StringBuilder()).append("specified file: '").append(requestedFile).append("'").toString();
else
propSrc = "default file in current working dir: 'quartz.properties'";
in = new BufferedInputStream(new FileInputStream(propFileName));
props.load(in);
}
catch(IOException ioe)
{
initException = new SchedulerException((new StringBuilder()).append("Properties file: '").append(propFileName).append("' could not be read.").toString(), ioe);
throw initException;
}
else
//如果org.quartz.propertiess属性文件不为null,则从当前Thread的ClassLoader的Context加载相应的属性文件
if(requestedFile != null)
{
in = Thread.currentThread().getContextClassLoader().getResourceAsStream(requestedFile);
if(in == null)
{
initException = new SchedulerException((new StringBuilder()).append("Properties file: '").append(requestedFile).append("' could not be found.").toString());
throw initException;
}
propSrc = (new StringBuilder()).append("specified file: '").append(requestedFile).append("' in the class resource path.").toString();
in = new BufferedInputStream(in);
try
{
props.load(in);
}
catch(IOException ioe)
{
initException = new SchedulerException((new StringBuilder()).append("Properties file: '").append(requestedFile).append("' could not be read.").toString(), ioe);
throw initException;
}
} else
{
propSrc = "default resource file in Quartz package: 'quartz.properties'";
ClassLoader cl = getClass().getClassLoader();
if(cl == null)
cl = findClassloader();
if(cl == null)
throw new SchedulerConfigException("Unable to find a class loader on the current thread or class.");
in = cl.getResourceAsStream("quartz.properties");
if(in == null)
in = cl.getResourceAsStream("/quartz.properties");
if(in == null)
in = cl.getResourceAsStream("org/quartz/quartz.properties");
if(in == null)
{
initException = new SchedulerException("Default quartz.properties not found in class path");
throw initException;
}
try
{
props.load(in);
}
catch(IOException ioe)
{
initException = new SchedulerException("Resource properties file: 'org/quartz/quartz.properties' could not be read from the classpath.", ioe);
throw initException;
}
}
if(in != null)
try
{
in.close();
}
catch(IOException ignore) { }
break MISSING_BLOCK_LABEL_502;
Exception exception;
exception;
if(in != null)
try
{
in.close();
}
catch(IOException ignore) { }
throw exception;
initialize(overrideWithSysProps(props));
return;
}
//重载系统属性
private Properties overrideWithSysProps(Properties props)
{
Properties sysProps = null;
try
{
sysProps = System.getProperties();
}
catch(AccessControlException e)
{
getLog().warn("Skipping overriding quartz properties with System properties during initialization because of an AccessControlException. This is likely due to not having read/write access for java.util.PropertyPermission as required by java.lang.System.getProperties(). To resolve this warning, either add this permission to your policy file or use a non-default version of initialize().", e);
}
if(sysProps != null)
props.putAll(sysProps);
return props;
}
//初始化PropertiesParser
public void initialize(Properties props)
throws SchedulerException
{
if(propSrc == null)
propSrc = "an externally provided properties instance.";
cfg = new PropertiesParser(props);
}
//初始化Quartz属性,线程池,线程数,线程优先级,job存储容器
private Scheduler instantiate()
throws SchedulerException
{
JobStore js;//job存储器
ThreadPool tp;// 线程池
QuartzScheduler qs;
DBConnectionManager dbMgr;//数据库连接管理器
ThreadExecutor threadExecutor;//线程执行器
SchedulerRepository schedRep;//调度器仓库
boolean makeSchedulerThreadDaemon;//Scheduler调度线程方式前台,守候
boolean threadsInheritInitalizersClassLoader;//线程初始化继承属性
long batchTimeWindow;
int maxBatchSize;
if(cfg == null)//initialize(Properties props)已经初始化cfg
initialize();
if(initException != null)
throw initException;
//初始化相关属性
schedRep = SchedulerRepository.getInstance();
schedName = cfg.getStringProperty("org.quartz.scheduler.instanceName", "QuartzScheduler");
threadName = cfg.getStringProperty("org.quartz.scheduler.threadName", (new StringBuilder()).append(schedName).append("_QuartzSchedulerThread").toString());
schedInstId = cfg.getStringProperty("org.quartz.scheduler.instanceId", "NON_CLUSTERED")
String classLoadHelperClass = cfg.getStringProperty("org.quartz.scheduler.classLoadHelper.class", "org.quartz.simpl.CascadingClassLoadHelper");
String jobFactoryClass = cfg.getStringProperty("org.quartz.scheduler.jobFactory.class", null);
batchTimeWindow = cfg.getLongProperty("org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow", 0L);
maxBatchSize = cfg.getIntProperty("org.quartz.scheduler.batchTriggerAcquisitionMaxCount", 1);
jmxExport = cfg.getBooleanProperty("org.quartz.scheduler.jmx.export");
jmxObjectName = cfg.getStringProperty("org.quartz.scheduler.jmx.objectName");
boolean jmxProxy = cfg.getBooleanProperty("org.quartz.scheduler.jmx.proxy");
String jmxProxyClass = cfg.getStringProperty("org.quartz.scheduler.jmx.proxy.class");
loadHelper.initialize();
//初始化JMX Proxy
if(jmxProxy)
{
if(autoId)
schedInstId = "NON_CLUSTERED";
if(jmxProxyClass == null)
throw new SchedulerConfigException("No JMX Proxy Scheduler class provided");
RemoteMBeanScheduler jmxScheduler = null;
try
{
jmxScheduler = (RemoteMBeanScheduler)loadHelper.loadClass(jmxProxyClass).newInstance();
}
if(jmxObjectName == null)
jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId);
jmxScheduler.setSchedulerObjectName(jmxObjectName);
tProps = cfg.getPropertyGroup("org.quartz.scheduler.jmx.proxy", true);
try
{
setBeanProps(jmxScheduler, tProps);
}
jmxScheduler.initialize();
schedRep.bind(jmxScheduler);
return jmxScheduler;
}
jobFactory = null;
//初始化jobFactory
if(jobFactoryClass != null)
{
try
{
jobFactory = (jobFactory)loadHelper.loadClass(jobFactoryClass).newInstance();
}
tProps = cfg.getPropertyGroup("org.quartz.scheduler.jobFactory", true);
try
{
setBeanProps(jobFactory, tProps);
}
}
//加载JobStore,org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
try
{
js = (JobStore)loadHelper.loadClass(jsClass).newInstance();
}
//如果org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX ,配置数据库信息
String dsNames[] = cfg.getPropertyGroups("org.quartz.dataSource");
for(int i = 0; i < dsNames.length; i++)
{
PropertiesParser pp = new PropertiesParser(cfg.getPropertyGroup((new StringBuilder()).append("org.quartz.dataSource.").append(dsNames[i]).toString(), true));
String cpClass = pp.getStringProperty("connectionProvider.class", null);
if(cpClass != null)
{
ConnectionProvider cp = null;
try
{
cp = (ConnectionProvider)loadHelper.loadClass(cpClass).newInstance();
}
try
{
pp.getUnderlyingProperties().remove("connectionProvider.class");
setBeanProps(cp, pp.getUnderlyingProperties());
cp.initialize();
}
dbMgr = DBConnectionManager.getInstance();
dbMgr.addConnectionProvider(dsNames[i], cp);
continue;
}
try
{
PoolingConnectionProvider cp = new PoolingConnectionProvider(pp.getUnderlyingProperties());
dbMgr = DBConnectionManager.getInstance();
dbMgr.addConnectionProvider(dsNames[i], cp);
continue;
}
}
//初始化插件
pluginNames = cfg.getPropertyGroups("org.quartz.plugin");
plugins = new SchedulerPlugin[pluginNames.length];
for(int i = 0; i < pluginNames.length; i++)
{
Properties pp = cfg.getPropertyGroup((new StringBuilder()).append("org.quartz.plugin.").append(pluginNames[i]).toString(), true);
String plugInClass = pp.getProperty("class", null);
if(plugInClass == null)
{
initException = new SchedulerException((new StringBuilder()).append("SchedulerPlugin class not specified for plugin '").append(pluginNames[i]).append("'").toString());
throw initException;
}
SchedulerPlugin plugin = null;
try
{
plugin = (SchedulerPlugin)loadHelper.loadClass(plugInClass).newInstance();
}
try
{
setBeanProps(plugin, pp);
}
plugins[i] = plugin;
}
//job监听器
String jobListenerNames[] = cfg.getPropertyGroups("org.quartz.jobListener");
jobListeners = new JobListener[jobListenerNames.length];
for(int i = 0; i < jobListenerNames.length; i++)
{
Properties lp = cfg.getPropertyGroup((new StringBuilder()).append("org.quartz.jobListener.").append(jobListenerNames[i]).toString(), true);
String listenerClass = lp.getProperty("class", null);
if(listenerClass == null)
{
initException = new SchedulerException((new StringBuilder()).append("JobListener class not specified for listener '").append(jobListenerNames[i]).append("'").toString());
throw initException;
}
JobListener listener = null;
try
{
listener = (JobListener)loadHelper.loadClass(listenerClass).newInstance();
}
try
{
Method nameSetter = null;
try
{
nameSetter = listener.getClass().getMethod("setName", strArg);
}
if(nameSetter != null)
nameSetter.invoke(listener, new Object[] {
jobListenerNames[i]
});
setBeanProps(listener, lp);
}
jobListeners[i] = listener;
}
//Trrige监听器
String triggerListenerNames[] = cfg.getPropertyGroups("org.quartz.triggerListener");
triggerListeners = new TriggerListener[triggerListenerNames.length];
for(int i = 0; i < triggerListenerNames.length; i++)
{
Properties lp = cfg.getPropertyGroup((new StringBuilder()).append("org.quartz.triggerListener.").append(triggerListenerNames[i]).toString(), true);
String listenerClass = lp.getProperty("class", null);
if(listenerClass == null)
{
initException = new SchedulerException((new StringBuilder()).append("TriggerListener class not specified for listener '").append(triggerListenerNames[i]).append("'").toString());
throw initException;
}
TriggerListener listener = null;
try
{
listener = (TriggerListener)loadHelper.loadClass(listenerClass).newInstance();
}
try
{
Method nameSetter = null;
try
{
nameSetter = listener.getClass().getMethod("setName", strArg);
}
if(nameSetter != null)
nameSetter.invoke(listener, new Object[] {
triggerListenerNames[i]
});
setBeanProps(listener, lp);
}
triggerListeners[i] = listener;
}
//初始化线程池执行类
String threadExecutorClass = cfg.getStringProperty("org.quartz.threadExecutor.class");
if(threadExecutorClass != null)
{
tProps = cfg.getPropertyGroup("org.quartz.threadExecutor", true);
try
{
threadExecutor = (ThreadExecutor)loadHelper.loadClass(threadExecutorClass).newInstance();
log.info((new StringBuilder()).append("Using custom implementation for ThreadExecutor: ").append(threadExecutorClass).toString());
setBeanProps(threadExecutor, tProps);
}
} else
{
log.info("Using default implementation for ThreadExecutor");
threadExecutor = new DefaultThreadExecutor();
}
Scheduler scheduler;
//初始化job执行器
JobRunShellFactory jrsf = null;
if(userTXLocation != null)
UserTransactionHelper.setUserTxLocation(userTXLocation);
if(wrapJobInTx)
jrsf = new JTAJobRunShellFactory();
else
jrsf = new JTAAnnotationAwareJobRunShellFactory();
if(autoId)
try
{
schedInstId = "NON_CLUSTERED";
if(js.isClustered())
schedInstId = instanceIdGenerator.generateInstanceId();
}
catch(Exception e)
{
getLog().error("Couldn't generate instance Id!", e);
throw new IllegalStateException("Cannot run without an instance id.");
}
if(js.getClass().getName().startsWith("org.terracotta.quartz"))
{
try
{
String uuid = (String)js.getClass().getMethod("getUUID", new Class[0]).invoke(js, new Object[0]);
if(schedInstId.equals("NON_CLUSTERED"))
{
schedInstId = (new StringBuilder()).append("TERRACOTTA_CLUSTERED,node=").append(uuid).toString();
if(jmxObjectName == null)
jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId);
} else
if(jmxObjectName == null)
jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, (new StringBuilder()).append(schedInstId).append(",node=").append(uuid).toString());
}
catch(Exception e)
{
throw new RuntimeException("Problem obtaining node id from TerracottaJobStore.", e);
}
if(null == cfg.getStringProperty("org.quartz.scheduler.jmx.export"))
jmxExport = true;
}
if(js instanceof JobStoreSupport)
{
JobStoreSupport jjs = (JobStoreSupport)js;
jjs.setDbRetryInterval(dbFailureRetry);
if(threadsInheritInitalizersClassLoader)
jjs.setThreadsInheritInitializersClassLoadContext(threadsInheritInitalizersClassLoader);
jjs.setThreadExecutor(threadExecutor);
}
//QuartzScheduler资源管理器
QuartzSchedulerResources rsrcs = new QuartzSchedulerResources();
rsrcs.setName(schedName);
rsrcs.setThreadName(threadName);
rsrcs.setInstanceId(schedInstId);
rsrcs.setJobRunShellFactory(jrsf);
rsrcs.setMakeSchedulerThreadDaemon(makeSchedulerThreadDaemon);
rsrcs.setThreadsInheritInitializersClassLoadContext(threadsInheritInitalizersClassLoader);
rsrcs.setRunUpdateCheck(!skipUpdateCheck);
rsrcs.setBatchTimeWindow(batchTimeWindow);
rsrcs.setMaxBatchSize(maxBatchSize);
rsrcs.setInterruptJobsOnShutdown(interruptJobsOnShutdown);
rsrcs.setInterruptJobsOnShutdownWithWait(interruptJobsOnShutdownWithWait);
rsrcs.setJMXExport(jmxExport);
rsrcs.setJMXObjectName(jmxObjectName);
if(managementRESTServiceEnabled)
{
ManagementRESTServiceConfiguration managementRESTServiceConfiguration = new ManagementRESTServiceConfiguration();
managementRESTServiceConfiguration.setBind(managementRESTServiceHostAndPort);
managementRESTServiceConfiguration.setEnabled(managementRESTServiceEnabled);
rsrcs.setManagementRESTServiceConfiguration(managementRESTServiceConfiguration);
}
if(rmiExport)
{
rsrcs.setRMIRegistryHost(rmiHost);
rsrcs.setRMIRegistryPort(rmiPort);
rsrcs.setRMIServerPort(rmiServerPort);
rsrcs.setRMICreateRegistryStrategy(rmiCreateRegistry);
rsrcs.setRMIBindName(rmiBindName);
}
SchedulerDetailsSetter.setDetails(tp, schedName, schedInstId);
rsrcs.setThreadExecutor(threadExecutor);
//线程池初始化
threadExecutor.initialize();
rsrcs.setThreadPool(tp);
if((tp instanceof SimpleThreadPool) && threadsInheritInitalizersClassLoader)
((SimpleThreadPool)tp).setThreadsInheritContextClassLoaderOfInitializingThread(threadsInheritInitalizersClassLoader);
tp.initialize();
tpInited = true;
rsrcs.setJobStore(js);
for(int i = 0; i < plugins.length; i++)
rsrcs.addSchedulerPlugin(plugins[i]);
//新建QuartzScheduler
qs = new QuartzScheduler(rsrcs, idleWaitTime, dbFailureRetry);
qsInited = true;
//初始化scheduler
scheduler = instantiate(rsrcs, qs);
if(jobFactory != null)
qs.setJobFactory(jobFactory);
for(int i = 0; i < plugins.length; i++)
plugins[i].initialize(pluginNames[i], scheduler, loadHelper);
for(int i = 0; i < jobListeners.length; i++)
qs.getListenerManager().addJobListener(jobListeners[i], EverythingMatcher.allJobs());
for(int i = 0; i < triggerListeners.length; i++)
qs.getListenerManager().addTriggerListener(triggerListeners[i], EverythingMatcher.allTriggers());
Object key;
String val;
for(Iterator i$ = schedCtxtProps.keySet().iterator(); i$.hasNext(); scheduler.getContext().put((String)key, val))
{
key = i$.next();
val = schedCtxtProps.getProperty((String)key);
}
js.setInstanceId(schedInstId);
js.setInstanceName(schedName);
js.setThreadPoolSize(tp.getPoolSize());
js.initialize(loadHelper, qs.getSchedulerSignaler());
jrsf.initialize(scheduler);
qs.initialize();
getLog().info((new StringBuilder()).append("Quartz scheduler '").append(scheduler.getSchedulerName()).append("' initialized from ").append(propSrc).toString());
getLog().info((new StringBuilder()).append("Quartz scheduler version: ").append(qs.getVersion()).toString());
qs.addNoGCObject(schedRep);
if(dbMgr != null)
qs.addNoGCObject(dbMgr);
//绑定scheduler到调度器仓库
schedRep.bind(scheduler);
return scheduler;//实际为QuartzScheduler
}
//初始化Scheduler
protected Scheduler instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs)
{
Scheduler scheduler = new StdScheduler(qs);
return scheduler;
}
//解析quartz.properties配置文件属性
private PropertiesParser cfg;
}
//调度器仓库
public class SchedulerRepository
{
private SchedulerRepository()
{
schedulers = new HashMap();
}
//获取调度器仓库单例
public static synchronized SchedulerRepository getInstance()
{
if(inst == null)
inst = new SchedulerRepository();
return inst;
}
//添加调度器到仓库
public synchronized void bind(Scheduler sched)
throws SchedulerException
{
if((Scheduler)schedulers.get(sched.getSchedulerName()) != null)
{
throw new SchedulerException((new StringBuilder()).append("Scheduler with name '").append(sched.getSchedulerName()).append("' already exists.").toString());
} else
{
schedulers.put(sched.getSchedulerName(), sched);
return;
}
}
public synchronized boolean remove(String schedName)
{
return schedulers.remove(schedName) != null;
}
//根据调度器name,寻到对应的Scheduler
public synchronized Scheduler lookup(String schedName)
{
return (Scheduler)schedulers.get(schedName);
}
public synchronized Collection lookupAll()
{
return Collections.unmodifiableCollection(schedulers.values());
}
private HashMap schedulers;//Hash<String,Scheduler>
private static SchedulerRepository inst;
}
//标准执行器实际上是包装了QuartzScheduler
public class StdScheduler
implements Scheduler
{
public StdScheduler(QuartzScheduler sched)
{
this.sched = sched;
}
private QuartzScheduler sched;
}
//调度器
public class QuartzScheduler
implements RemotableQuartzScheduler
{
public QuartzScheduler(QuartzSchedulerResources resources, long idleWaitTime, long dbRetryInterval)
throws SchedulerException
{
}
private static String VERSION_MAJOR;
private static String VERSION_MINOR;
private static String VERSION_ITERATION;
private QuartzSchedulerResources resources;
private QuartzSchedulerThread schedThread;
private ThreadGroup threadGroup;
private SchedulerContext context;
private ListenerManager listenerManager;
private HashMap internalJobListeners;
private HashMap internalTriggerListeners;
private ArrayList internalSchedulerListeners;
private JobFactory jobFactory;
ExecutingJobsManager jobMgr;
ErrorLogger errLogger;
private SchedulerSignaler signaler;
private Random random;
private ArrayList holdToPreventGC;
private boolean signalOnSchedulingChange;
private volatile boolean closed;
private volatile boolean shuttingDown;
private boolean boundRemotely;
private QuartzSchedulerMBean jmxBean;
private Date initialStart;
private final Timer updateTimer;
private final Logger log = LoggerFactory.getLogger(getClass());
}
//QuartzScheduler的资源管理器
public class QuartzSchedulerResources
{
public static final String CREATE_REGISTRY_NEVER = "never";
public static final String CREATE_REGISTRY_ALWAYS = "always";
public static final String CREATE_REGISTRY_AS_NEEDED = "as_needed";
private String name;
private String instanceId;
private String threadName;
private String rmiRegistryHost;
private int rmiRegistryPort;
private int rmiServerPort;
private String rmiCreateRegistryStrategy;
private ThreadPool threadPool;
private JobStore jobStore;
private JobRunShellFactory jobRunShellFactory;
private List schedulerPlugins;
private boolean makeSchedulerThreadDaemon;
private boolean threadsInheritInitializersClassLoadContext;
private String rmiBindName;
private boolean jmxExport;
private String jmxObjectName;
private ManagementRESTServiceConfiguration managementRESTServiceConfiguration;
private ThreadExecutor threadExecutor;
private boolean runUpdateCheck;
private long batchTimeWindow;
private int maxBatchSize;
private boolean interruptJobsOnShutdown;
private boolean interruptJobsOnShutdownWithWait;
}
从StdSchedulerFactory的getDefaultScheduler方法可以看出与getScheduler相同
总结:
从以上代码分析中,看出StdSchedulerFactory获取执行器,首先从调度器仓库获取调度器,如果为空,则配置属性cfg,如果cfg为空则初始化属性文件,如果没有配置属性文件,则加载默认属性;然后初始化调度器(线程池,存储器,job,trriger监控器,JMX,及调度器仓库,如果存储器为JobStoreTX ,则初始化数据库信息);从返回的调度器来看实际上就是QuartzScheduler