![](http://static.oschina.net/uploads/space/2015/1125/144016_NNaq_1989867.png)
2. 类
package org.springframework.scheduling.quartz;
import java.util.Map;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* Convenience subclass of Quartz' JobDetail class that eases bean-style
* usage.
*
* itself is already a JavaBean but lacks
* sensible defaults. This class uses the Spring bean name as job name,
* and the Quartz default group ("DEFAULT") as job group if not specified.
*/
public class JobDetailBean extends JobDetail
implements BeanNameAware, ApplicationContextAware, InitializingBean {
private Class actualJobClass;
private String beanName;
private ApplicationContext applicationContext;
private String applicationContextJobDataKey;
/**
* Overridden to support any job class, to allow a custom JobFactory
* to adapt the given job class to the Quartz Job interface.
* @see SchedulerFactoryBean#setJobFactory
*/
public void setJobClass(Class jobClass) {
if (jobClass != null && !Job.class.isAssignableFrom(jobClass)) {
super.setJobClass(DelegatingJob.class);
this.actualJobClass = jobClass;
}
else {
super.setJobClass(jobClass);
}
}
/**
* Overridden to support any job class, to allow a custom JobFactory
* to adapt the given job class to the Quartz Job interface.
*/
public Class getJobClass() {
return (this.actualJobClass != null ? this.actualJobClass : super.getJobClass());
}
/**
* Register objects in the JobDataMap via a given Map.
* <p>These objects will be available to this Job only,
* in contrast to objects in the SchedulerContext.
* 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.
*/
public void setJobDataAsMap(Map jobDataAsMap) {
getJobDataMap().putAll(jobDataAsMap);
}
/**
* Set a list of JobListener names for this job, referring to
* non-global JobListeners registered with the Scheduler.
* <p>A JobListener name always refers to the name returned
* by the JobListener implementation.
*/
public void setJobListenerNames(String[] names) {
for (int i = 0; i < names.length; i++) {
addJobListener(names[i]);
}
}
public void setBeanName(String beanName) {
this.beanName = beanName;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
/**
* Set the key of an ApplicationContext reference to expose in the JobDataMap,
* for example "applicationContext". Default is none.
* Only applicable when running in a Spring ApplicationContext.
* <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 responsible for the lifecycle of its Jobs.
* <p><b>Note: When using persistent job stores where JobDetail contents will
* be kept in the database, do not put an ApplicationContext reference into
* the JobDataMap but rather into the SchedulerContext.</b>
* @see SchedulerFactoryBean#setApplicationContextSchedulerContextKey
* @see org.springframework.context.ApplicationContext
*/
public void setApplicationContextJobDataKey(String applicationContextJobDataKey) {
this.applicationContextJobDataKey = applicationContextJobDataKey;
}
public void afterPropertiesSet() {
if (getName() == null) {
setName(this.beanName);
}
if (getGroup() == null) {
setGroup(Scheduler.DEFAULT_GROUP);
}
if (this.applicationContextJobDataKey != null) {
if (this.applicationContext == null) {
throw new IllegalStateException(
"JobDetailBean needs to be set up in an ApplicationContext " +
"to be able to handle an 'applicationContextJobDataKey'");
}
getJobDataMap().put(this.applicationContextJobDataKey, this.applicationContext);
}
}
}
JobDetail.java
package org.quartz;
import java.util.ArrayList;
/**
* Conveys the detail properties of a given <code>Job</code> instance.
*
* Quartz does not store an actual instance of a <code>Job</code> class, but
* instead allows you to define an instance of one, through the use of a <code>JobDetail</code>.
* </p>
*
* <p>
* <code>Job</code> s have a name and group associated with them, which
* should uniquely identify them within a single <code>{@link Scheduler}</code>.
* </p>
*
* <p>
* <code>Trigger</code> s are the 'mechanism' by which <code>Job</code> s
* are scheduled. Many <code>Trigger</code> s can point to the same <code>Job</code>,
* but a single <code>Trigger</code> can only point to one <code>Job</code>.
* </p>
*/
public class JobDetail implements Cloneable, java.io.Serializable {
private String name;
private String group = Scheduler.DEFAULT_GROUP;
private String description;
private Class jobClass;
private JobDataMap jobDataMap;
private boolean volatility = false;
private boolean durability = false;
private boolean shouldRecover = false;
private ArrayList jobListeners = new ArrayList(2);
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Constructors.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
* Create a <code>JobDetail</code> with no specified name or group, and
* the default settings of all the other properties.
*
* <p>
* Note that the {@link #setName(String)},{@link #setGroup(String)}and
* {@link #setJobClass(Class)}methods must be called before the job can be
* placed into a {@link Scheduler}
* </p>
*/
public JobDetail() {
// do nothing...
}
/**
* Create a <code>JobDetail</code> with the given name, and group, and
* the default settings of all the other properties.
*
* @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.
*
* @exception IllegalArgumentException
* if nameis null or empty, or the group is an empty string.
*/
public JobDetail(String name, String group, Class jobClass) {
setName(name);
setGroup(group);
setJobClass(jobClass);
}
/**
* Create a <code>JobDetail</code> with the given name, and group, and
* the given settings of all the other properties.
*
* @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.
*
* @exception IllegalArgumentException
* if nameis null or empty, or the group is an empty string.
*/
public JobDetail(String name, String group, Class jobClass,
boolean volatility, boolean durability, boolean recover) {
setName(name);
setGroup(group);
setJobClass(jobClass);
setVolatility(volatility);
setDurability(durability);
setRequestsRecovery(recover);
}
/*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Interface.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/**
* Get the name of this <code>Job</code>.
*/
public String getName() {
return name;
}
/**
* Set the name of this <code>Job</code>.
*
* @exception IllegalArgumentException
* if name is null or empty.
*/
public void setName(String name) {
if (name == null || name.trim().length() == 0)
throw new IllegalArgumentException("Job name cannot be empty.");
this.name = name;
}
/**
* Get the group of this <code>Job</code>.
*/
public String getGroup() {
return group;
}
/**
* Set the group of this <code>Job</code>.
*
* @param group if <code>null</code>, Scheduler.DEFAULT_GROUP will be used.
* @exception IllegalArgumentException
* if the group is an empty string.
*/
public void setGroup(String group) {
if (group != null && group.trim().length() == 0)
throw new IllegalArgumentException(
"Group name cannot be empty.");
if(group == null)
group = Scheduler.DEFAULT_GROUP;
this.group = group;
}
/**
* Returns the 'full name' of the <code>Trigger</code> in the format
* "group.name".
*/
public String getFullName() {
return group + "." + name;
}
/**
* Return the description given to the <code>Job</code> instance by its
* creator (if any).
* @return null if no description was set.
*/
public String getDescription() {
return description;
}
/**
* Set a description for the <code>Job</code> instance - may be useful
* for remembering/displaying the purpose of the job, though the
* description has no meaning to Quartz.
*/
public void setDescription(String description) {
this.description = description;
}
/**
* Get the instance of <code>Job</code> that will be executed.
*/
public Class getJobClass() {
return jobClass;
}
/**
* Set the instance of <code>Job</code> that will be executed.
*
* @exception IllegalArgumentException
* if jobClass is null or the class is not a <code>Job</code>.
*/
public void setJobClass(Class jobClass) {
if (jobClass == null)
throw new IllegalArgumentException("Job class cannot be null.");
if (!Job.class.isAssignableFrom(jobClass))
throw new IllegalArgumentException(
"Job class must implement the Job interface.");
this.jobClass = jobClass;
}
/**
* Get the <code>JobDataMap</code> that is associated with the <code>Job</code>.
*/
public JobDataMap getJobDataMap() {
if (jobDataMap == null) jobDataMap = new JobDataMap();
return jobDataMap;
}
/**
* Set the <code>JobDataMap</code> to be associated with the <code>Job</code>.
*/
public void setJobDataMap(JobDataMap jobDataMap) {
this.jobDataMap = jobDataMap;
}
/**
* Validates whether the properties of the <code>JobDetail</code> are
* valid for submission into a <code>Scheduler</code>.
*
* @throws IllegalStateException
* if a required property (such as Name, Group, Class) is not
* set.
*/
public void validate() throws SchedulerException {
if (name == null)
throw new SchedulerException("Job's name cannot be null",
SchedulerException.ERR_CLIENT_ERROR);
if (group == null)
throw new SchedulerException("Job's group cannot be null",
SchedulerException.ERR_CLIENT_ERROR);
if (jobClass == null)
throw new SchedulerException("Job's class cannot be null",
SchedulerException.ERR_CLIENT_ERROR);
}
/**
* Set whether or not the <code>Job</code> should be persisted in the
* <code>{@link org.quartz.spi.JobStore}</code> for re-use after program
* restarts.
*
* <p>
* If not explicitly set, the default value is <code>false</code>.
* </p>
*/
public void setVolatility(boolean volatility) {
this.volatility = volatility;
}
/**
* Set whether or not the <code>Job</code> should remain stored after it
* is orphaned (no <code>{@link Trigger}s</code> point to it).
*
* If not explicitly set, the default value is <code>false</code>.
*/
public void setDurability(boolean durability) {
this.durability = durability;
}
/**
* Set whether or not the the <code>Scheduler</code> should re-execute
* the <code>Job</code> if a 'recovery' or 'fail-over' situation is
* encountered.
*
* If not explicitly set, the default value is <code>false</code>.
*
* @see JobExecutionContext#isRecovering()
* @see JobExecutionContext#isFailedOver()
*/
public void setRequestsRecovery(boolean shouldRecover) {
this.shouldRecover = shouldRecover;
}
/**
* Whether or not the <code>Job</code> should not be persisted in the
* <code>{@link org.quartz.spi.JobStore}</code> for re-use after program
* restarts.
*
* If not explicitly set, the default value is <code>false</code>.
*
* @return <code>true</code> if the <code>Job</code> should be garbage
* collected along with the <code>{@link Scheduler}</code>.
*/
public boolean isVolatile() {
return volatility;
}
/**
* Whether or not the <code>Job</code> should remain stored after it is
* orphaned (no <code>{@link Trigger}s</code> point to it).
*
* If not explicitly set, the default value is <code>false</code>.
*
* @return <code>true</code> if the Job should remain persisted after
* being orphaned.
*/
public boolean isDurable() {
return durability;
}
/**
* Whether or not the <code>Job</code> implements the interface <code>{@link StatefulJob}</code>.
*/
public boolean isStateful() {
if (jobClass == null)
return false;
return (StatefulJob.class.isAssignableFrom(jobClass));
}
/**
* Instructs the <code>Scheduler</code> whether or not the <code>Job</code>
* should be re-executed if a 'recovery' or 'fail-over' situation is
* encountered.
*
* If not explicitly set, the default value is <code>false</code>.
*
* @see JobExecutionContext#isRecovering()
* @see JobExecutionContext#isFailedOver()
*/
public boolean requestsRecovery() {
return shouldRecover;
}
/**
* Add the specified name of a <code>{@link JobListener}</code> to the
* end of the <code>Job</code>'s list of listeners.
*/
public void addJobListener(String name) {
jobListeners.add(name);
}
/**
* Remove the specified name of a <code>{@link JobListener}</code> from
* the <code>Job</code>'s list of listeners.
*
* @return true if the given name was found in the list, and removed
*/
public boolean removeJobListener(String name) {
return jobListeners.remove(name);
}
/**
* Returns an array of <code>String</code> s containing the names of all
* <code>{@link JobListener}</code> s assigned to the <code>Job</code>,
* in the order in which they should be notified.
*/
public String[] getJobListenerNames() {
return (String[]) jobListeners.toArray(new String[jobListeners.size()]);
}
/**
* Return a simple string representation of this object.
*/
public String toString() {
return "JobDetail '" + getFullName() + "': jobClass: '"
+ ((getJobClass() == null) ? null : getJobClass().getName())
+ " isStateful: " + isStateful() + " isVolatile: "
+ isVolatile() + " isDurable: " + isDurable()
+ " requestsRecovers: " + requestsRecovery();
}
public Object clone() {
JobDetail copy;
try {
copy = (JobDetail) super.clone();
copy.jobListeners = (ArrayList) jobListeners.clone();
if (jobDataMap != null)
copy.jobDataMap = (JobDataMap) jobDataMap.clone();
} catch (CloneNotSupportedException ex) {
throw new IncompatibleClassChangeError("Not Cloneable.");
}
return copy;
}
}
3. 说明
<1> 常用的构造方法-----public JobDetail(String name, String group, Class jobClass)
<2> 比较重要的属性JobDataMap----可以传递参数。