1. MyMethodInvokingBean
package cn.xue.Scheduler.service;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.StatefulJob;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.util.MethodInvoker;
public class MyMethodInvokingBean implements FactoryBean, BeanNameAware, InitializingBean
{
private Log logger = LogFactory.getLog(getClass());
/**
* The JobDetail produced by the <code>afterPropertiesSet</code> method of this Class will be assigned to the Group specified by this property. Default: Scheduler.DEFAULT_GROUP
* @see #afterPropertiesSet()
* @see Scheduler#DEFAULT_GROUP
*/
private String group = Scheduler.DEFAULT_GROUP;
/**
* Indicates whether or not the Bean Method should be invoked by more than one Scheduler at the specified time (like when deployed to a cluster, and/or when there are multiple Spring ApplicationContexts in a single JVM<i> - Tomcat 5.5 creates 2 or more instances of the DispatcherServlet (a pool), which in turn creates a separate Spring ApplicationContext for each instance of the servlet</i>)
* <p>
* Used by <code>afterPropertiesSet</code> to set the JobDetail.jobClass to MethodInvokingJob.class or StatefulMethodInvokingJob.class when true or false, respectively. Default: true
* @see #afterPropertiesSet()
*/
private boolean concurrent = true;
/** Used to set the JobDetail.durable property. Default: false
* <p>Durability - if a job is non-durable, it is automatically deleted from the scheduler once there are no longer any active triggers associated with it.
* @see <a href="http://www.opensymphony.com/quartz/wikidocs/TutorialLesson3.html">http://www.opensymphony.com/quartz/wikidocs/TutorialLesson3.html</a>
* @see #afterPropertiesSet()
*/
private boolean durable = false;
/**
* Used by <code>afterPropertiesSet</code> to set the JobDetail.volatile property. Default: false
* <p>Volatility - if a job is volatile, it is not persisted between re-starts of the Quartz scheduler.
* <p>I set the default to false to be the same as the default for a Quartz Trigger. An exception is thrown
* when the Trigger is non-volatile and the Job is volatile. If you want volatility, then you must set this property, and the Trigger's volatility property, to true.
* @see <a href="http://www.opensymphony.com/quartz/wikidocs/TutorialLesson3.html">http://www.opensymphony.com/quartz/wikidocs/TutorialLesson3.html</a>
* @see #afterPropertiesSet()
*/
private boolean volatility = false;
/**
* Used by <code>afterPropertiesSet</code> to set the JobDetail.requestsRecovery property. Default: false<BR>
* <p>RequestsRecovery - if a job "requests recovery", and it is executing during the time of a 'hard shutdown' of the scheduler (i.e. the process it is running within crashes, or the machine is shut off), then it is re-executed when the scheduler is started again. In this case, the JobExecutionContext.isRecovering() method will return true.
* @see <a href="http://www.opensymphony.com/quartz/wikidocs/TutorialLesson3.html">http://www.opensymphony.com/quartz/wikidocs/TutorialLesson3.html</a>
* @see #afterPropertiesSet()
*/
private boolean shouldRecover = false;
/**
* A list of names of JobListeners to associate with the JobDetail object created by this FactoryBean.
*
* @see #afterPropertiesSet()
**/
private String[] jobListenerNames;
/** The name assigned to this bean in the Spring ApplicationContext.
* Used by <code>afterPropertiesSet</code> to set the JobDetail.name property.
* @see afterPropertiesSet()
* @see JobDetail#setName(String)
**/
private String beanName;
/**
* The JobDetail produced by the <code>afterPropertiesSet</code> method, and returned by the <code>getObject</code> method of the Spring FactoryBean interface.
* @see #afterPropertiesSet()
* @see #getObject()
* @see FactoryBean
**/
private JobDetail jobDetail;
/**
* The name of the Class to invoke.
**/
private String targetClass;
/**
* The Object to invoke.
* <p>
* {@link #targetClass} or targetObject must be set, but not both.
* <p>
* This object must be Serializable when {@link #concurrent} is set to false.
*/
private Object targetObject;
/**
* The instance method to invoke on the Class or Object identified by the targetClass or targetObject property, respectfully.
* <p>
* targetMethod or {@link #staticMethod} should be set, but not both.
**/
private String targetMethod;
/**
* The static method to invoke on the Class or Object identified by the targetClass or targetObject property, respectfully.
* <p>
* {@link #targetMethod} or staticMethod should be set, but not both.
*/
private String staticMethod;
/**
* Method arguments provided to the {@link #targetMethod} or {@link #staticMethod} specified.
* <p>
* All arguments must be Serializable when {@link #concurrent} is set to false.
* <p>
* I strongly urge you not to provide arguments until Quartz 1.6.1 has been released if you are using a JDBCJobStore with
* Microsoft SQL Server. There is a bug in version 1.6.0 that prevents Quartz from Serializing the Objects in the JobDataMap
* to the database. The workaround is to set the property "org.opensymphony.quaryz.useProperties = true" in your quartz.properties file,
* which tells Quartz not to serialize Objects in the JobDataMap, but to instead expect all String compliant values.
*/
private Object[] arguments;
/**
* Get the targetClass property.
* @see #targetClass
* @return targetClass
*/
public String getTargetClass()
{
return targetClass;
}
/**
* Set the targetClass property.
* @see #targetClass
*/
public void setTargetClass(String targetClass)
{
this.targetClass = targetClass;
}
/**
* Get the targetMethod property.
* @see #targetMethod
* @return targetMethod
*/
public String getTargetMethod()
{
return targetMethod;
}
/**
* Set the targetMethod property.
* @see #targetMethod
*/
public void setTargetMethod(String targetMethod)
{
this.targetMethod = targetMethod;
}
/**
* @return jobDetail - The JobDetail that is created by the afterPropertiesSet method of this FactoryBean
* @see #jobDetail
* @see #afterPropertiesSet()
* @see FactoryBean#getObject()
*/
public Object getObject() throws Exception
{
return jobDetail;
}
/**
* @return JobDetail.class
* @see FactoryBean#getObjectType()
*/
public Class getObjectType()
{
return JobDetail.class;
}
/**
* @return true
* @see FactoryBean#isSingleton()
*/
public boolean isSingleton()
{
return true;
}
/**
* Set the beanName property.
* @see #beanName
* @see BeanNameAware#setBeanName(String)
*/
public void setBeanName(String beanName)
{
this.beanName = beanName;
}
/**
* Invoked by the Spring container after all properties have been set.
* <p>
* Sets the <code>jobDetail</code> property to a new instance of JobDetail
* <ul>
* <li>jobDetail.name is set to <code>beanName</code><br>
* <li>jobDetail.group is set to <code>group</code><br>
* <li>jobDetail.jobClass is set to MethodInvokingJob.class or StatefulMethodInvokingJob.class depending on whether the <code>concurrent</code> property is set to true or false, respectively.<br>
* <li>jobDetail.durability is set to <code>durable</code>
* <li>jobDetail.volatility is set to <code>volatility</code>
* <li>jobDetail.requestsRecovery is set to <code>shouldRecover</code>
* <li>jobDetail.jobDataMap["targetClass"] is set to <code>targetClass</code>
* <li>jobDetail.jobDataMap["targetMethod"] is set to <code>targetMethod</code>
* <li>Each JobListener name in <code>jobListenerNames</code> is added to the <code>jobDetail</code> object.
* </ul>
* <p>
* Logging occurs at the DEBUG and INFO levels; 4 lines at the DEBUG level, and 1 line at the INFO level.
* <ul>
* <li>DEBUG: start
* <li>DEBUG: Creating JobDetail <code>{beanName}</code>
* <li>DEBUG: Registering JobListener names with JobDetail object <code>{beanName}</code>
* <li>INFO: Created JobDetail: <code>{jobDetail}</code>; targetClass: <code>{targetClass}</code>; targetMethod: <code>{targetMethod}</code>;
* <li>DEBUG: end
* </ul>
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
* @see JobDetail
* @see #jobDetail
* @see #beanName
* @see #group
* @see MethodInvokingJob
* @see StatefulMethodInvokingJob
* @see #durable
* @see #volatility
* @see #shouldRecover
* @see #targetClass
* @see #targetMethod
* @see #jobListenerNames
*/
public void afterPropertiesSet() throws Exception
{
try
{
logger.debug("start");
logger.debug("Creating JobDetail "+beanName);
jobDetail = new JobDetail();
jobDetail.setName(beanName);
jobDetail.setGroup(group);
jobDetail.setJobClass(concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);
jobDetail.setDurability(durable);
jobDetail.setVolatility(volatility);
jobDetail.setRequestsRecovery(shouldRecover);
if(targetClass!=null)
jobDetail.getJobDataMap().put("targetClass", targetClass);
if(targetObject!=null)
jobDetail.getJobDataMap().put("targetObject", targetObject);
if(targetMethod!=null)
jobDetail.getJobDataMap().put("targetMethod", targetMethod);
if(staticMethod!=null)
jobDetail.getJobDataMap().put("staticMethod", staticMethod);
if(arguments!=null)
jobDetail.getJobDataMap().put("arguments", arguments);
logger.debug("Registering JobListener names with JobDetail object "+beanName);
if (this.jobListenerNames != null) {
for (int i = 0; i < this.jobListenerNames.length; i++) {
this.jobDetail.addJobListener(this.jobListenerNames[i]);
}
}
logger.info("Created JobDetail: "+jobDetail+"; targetClass: "+targetClass+"; targetObject: "+targetObject+"; targetMethod: "+targetMethod+"; staticMethod: "+staticMethod+"; arguments: "+arguments+";");
}
finally
{
logger.debug("end");
}
}
/**
* Setter for the concurrent property.
*
* @param concurrent
* @see #concurrent
*/
public void setConcurrent(boolean concurrent)
{
this.concurrent = concurrent;
}
/**
* setter for the durable property.
*
* @param durable
*
* @see #durable
*/
public void setDurable(boolean durable)
{
this.durable = durable;
}
/**
* setter for the group property.
*
* @param group
*
* @see #group
*/
public void setGroup(String group)
{
this.group = group;
}
/**
* setter for the {@link #jobListenerNames} property.
*
* @param jobListenerNames
* @see #jobListenerNames
*/
public void setJobListenerNames(String[] jobListenerNames)
{
this.jobListenerNames = jobListenerNames;
}
/**
* setter for the {@link #shouldRecover} property.
*
* @param shouldRecover
* @see #shouldRecover
*/
public void setShouldRecover(boolean shouldRecover)
{
this.shouldRecover = shouldRecover;
}
/**
* setter for the {@link #volatility} property.
*
* @param volatility
* @see #volatility
*/
public void setVolatility(boolean volatility)
{
this.volatility = volatility;
}
/**
* This is a cluster safe Job designed to invoke a method on any bean defined within the same Spring
* ApplicationContext.
* <p>
* The only entries this Job expects in the JobDataMap are "targetClass" and "targetMethod".<br>
* - It uses the value of the <code>targetClass</code> entry to get the desired bean from the Spring ApplicationContext.<br>
* - It uses the value of the <code>targetMethod</code> entry to determine which method of the Bean (identified by targetClass) to invoke.
* <p>
* It uses the static ApplicationContext in the MethodInvokingJobDetailFactoryBean,
* which is ApplicationContextAware, to get the Bean with which to invoke the method.
* <p>
* All Exceptions thrown from the execute method are caught and wrapped in a JobExecutionException.
*
* @see MyMethodInvokingBean#applicationContext
* @see #execute(JobExecutionContext)
*
* @author Stephen M. Wick
*/
public static class MethodInvokingJob implements Job
{
protected Log logger = LogFactory.getLog(getClass());
/**
* When invoked by a Quartz scheduler, <code>execute</code> invokes a method on a Class or Object in the JobExecutionContext provided.
* <p>
* <b>Implementation</b><br>
* The Class is identified by the "targetClass" entry in the JobDataMap of the JobExecutionContext provided. If targetClass is specified, then targetMethod must be a static method.<br>
* The Object is identified by the 'targetObject" entry in the JobDataMap of the JobExecutionContext provided. If targetObject is provided, then targetClass will be overwritten. This Object must be Serializable when <code>concurrent</code> is set to false.<br>
* The method is identified by the "targetMethod" entry in the JobDataMap of the JobExecutionContext provided.<br>
* The "staticMethod" entry in the JobDataMap of the JobExecutionContext can be used to specify a Class and Method in one entry (ie: "example.ExampleClass.someStaticMethod")<br>
* The method arguments (an array of Objects) are identified by the "arguments" entry in the JobDataMap of the JobExecutionContext. All arguments must be Serializable when <code>concurrent</code> is set to false.
* <p>
* Logging is provided at the DEBUG and INFO levels; 8 lines at the DEBUG level, and 1 line at the INFO level.
* @see Job#execute(JobExecutionContext)
*/
public void execute(JobExecutionContext context) throws JobExecutionException
{
try
{
logger.debug("start");
String targetClass = context.getMergedJobDataMap().getString("targetClass");
//logger.debug("targetClass is "+targetClass);
Class targetClassClass = null;
if(targetClass!=null){
targetClassClass = Class.forName(targetClass); // Could throw ClassNotFoundException
}
Object targetObject = context.getMergedJobDataMap().get("targetObject");
ApplicationContext ac = (ApplicationContext)context.getScheduler().getContext().get("applicationContext");
//logger.debug("targetObject is "+targetObject);
String targetMethod = context.getMergedJobDataMap().getString("targetMethod");
//logger.debug("targetMethod is "+targetMethod);
String staticMethod = context.getMergedJobDataMap().getString("staticMethod");
//logger.debug("staticMethod is "+staticMethod);
Object[] arguments = (Object[])context.getMergedJobDataMap().get("arguments");
//logger.debug("arguments are "+arguments);
arguments=new Object[1];
arguments[0]=ac;
//logger.debug("creating MethodInvoker");
MethodInvoker methodInvoker = new MethodInvoker();
methodInvoker.setTargetClass(targetClassClass);
methodInvoker.setTargetObject(targetObject);
methodInvoker.setTargetMethod(targetMethod);
methodInvoker.setStaticMethod(staticMethod);
methodInvoker.setArguments(arguments);
methodInvoker.prepare();
//logger.info("Invoking: "+methodInvoker.getPreparedMethod().toGenericString());
methodInvoker.invoke();
}
catch(Exception e)
{
throw new JobExecutionException(e);
}
finally
{
logger.debug("end");
}
}
}
public static class StatefulMethodInvokingJob extends MethodInvokingJob implements StatefulJob
{
// No additional functionality; just needs to implement StatefulJob.
}
public Object[] getArguments()
{
return arguments;
}
public void setArguments(Object[] arguments)
{
this.arguments = arguments;
}
public String getStaticMethod()
{
return staticMethod;
}
public void setStaticMethod(String staticMethod)
{
this.staticMethod = staticMethod;
}
public void setTargetObject(Object targetObject)
{
this.targetObject = targetObject;
}
}
2. SchedulerManager
package cn.xue.Scheduler.service;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerUtils;
import org.quartz.impl.calendar.AnnualCalendar;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
@Component("schedulerManager")
public class SchedulerManager {
private SchedulerFactoryBean schedulerFactoryBean;
@Autowired
public void setSchedulerFactoryBean(SchedulerFactoryBean schedulerFactoryBean) {
this.schedulerFactoryBean = schedulerFactoryBean;
}
public void addCalendarJob(Long l) throws ParseException, SchedulerException{
String jobName=l+"add_Job";
String triggerName=l+"add_Trigger";
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobDetail jobDetail = scheduler.getJobDetail(jobName, Scheduler.DEFAULT_GROUP);
if(jobDetail==null){
AnnualCalendar holidays = new AnnualCalendar(); //①法定节日是以每年为周期的,所以使用AnnualCalendar
Calendar laborDay = new GregorianCalendar(); //②五一劳动节
laborDay.add(Calendar.MONTH,5);
laborDay.add(Calendar.DATE,1);
holidays.setDayExcluded(laborDay, true); //②-1:排除的日期,如果设置为false则为包含
Calendar nationalDay = new GregorianCalendar(); //③国庆节
nationalDay.add(Calendar.MONTH,10);
nationalDay.add(Calendar.DATE,1);
holidays.setDayExcluded(nationalDay, true); //③-1:排除该日期
scheduler.addCalendar("holidays", holidays, false, false); //④向Scheduler注册日历
Date runDate = TriggerUtils.getDateOf(0,0, 10, 1, 4); //⑤4月1号 上午10点
JobDetail job = new JobDetail(jobName, Scheduler.DEFAULT_GROUP, MyJob1.class);
SimpleTrigger trigger = new SimpleTrigger(triggerName, Scheduler.DEFAULT_GROUP, runDate, null, SimpleTrigger.REPEAT_INDEFINITELY, 60L * 60L * 1000L);
trigger.setCalendarName("holidays"); //⑥让Trigger应用指定的日历规则
scheduler.scheduleJob(job, trigger);
scheduler.start();
}
/*
由于节日是每年重复的,所以使用org.quartz.Calendar的AnnualCalendar实现类,通过②、③的代码,指定五一和国庆两个节日并通过AnnualCalendar#setDayExcluded(Calendar day, boolean exclude)方法添加这两个日期。
exclude为true时表示排除指定的日期,如果为false时表示包含指定的日期。
在定制好org.quartz.Calendar后,还需要通过Scheduler#addCalendar(String calName, Calendar calendar, boolean replace, boolean updateTriggers)进行注册,
如果updateTriggers为true,Scheduler中已引用Calendar的Trigger将得到更新,如④所示。
在⑥处,我们让一个Trigger指定使用Scheduler中代表节日的Calendar,这样Trigger就会避开五一和国庆这两个特殊日子了。
*/
}
public void addJob(Long l) throws ParseException, SchedulerException{
String jobName=l+"add_Job";
String triggerName=l+"add_Trigger";
Scheduler scheduler = schedulerFactoryBean.getScheduler();
JobDetail jobDetail = scheduler.getJobDetail(jobName, Scheduler.DEFAULT_GROUP);
if(jobDetail==null){
jobDetail = new JobDetail(jobName, Scheduler.DEFAULT_GROUP,MyJob1.class);
jobDetail.getJobDataMap().put("xueyong", l);
Trigger trigger=new CronTrigger(triggerName,Scheduler.DEFAULT_GROUP, "0/5 * * * * ?" );
scheduler.scheduleJob(jobDetail, trigger); //注册并进行调度
scheduler.start();
}
}
//移除某一个项目的某一个周期性活动的job
public void removeJob(Long l) throws SchedulerException{
String jobName=l+"add_Job";
String triggerName=l+"add_Trigger";
Scheduler scheduler = schedulerFactoryBean.getScheduler();
scheduler.pauseTrigger(triggerName,Scheduler.DEFAULT_GROUP);//停止触发器
scheduler.unscheduleJob(triggerName,Scheduler.DEFAULT_GROUP);//移除触发器
scheduler.deleteJob(jobName,Scheduler.DEFAULT_GROUP);//删除任务
}
//修改job的触发时间
public void modifyJobTime(Long l ) throws SchedulerException, ParseException{
String jobName=l+"add_Job";
String triggerName=l+"add_Trigger";
Scheduler scheduler = schedulerFactoryBean.getScheduler(); //获取一个调度器实例
JobDetail jobDetail = scheduler.getJobDetail(jobName,Scheduler.DEFAULT_GROUP);
if(jobDetail != null){ //update time
CronTrigger cronTrigger = (CronTrigger)scheduler.getTrigger(triggerName,Scheduler.DEFAULT_GROUP);
cronTrigger.setCronExpression( "0/20 * * * * ?" );
scheduler.resumeTrigger(triggerName,Scheduler.DEFAULT_GROUP); //重启触发器
scheduler.rescheduleJob(cronTrigger.getName(), cronTrigger.getGroup(), cronTrigger);
}
}
}
3. MyJob1
package cn.xue.Scheduler.service;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerContext;
import org.quartz.SchedulerException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
import cn.xue.docModel.dao.LoopbkmkTreeDao;
public class MyJob1 extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
JobDataMap dataMap = context.getJobDetail().getJobDataMap();
String jobName = context.getJobDetail().getName();
String jobGroup = context.getJobDetail().getGroup();
Long projectID = (Long)dataMap.get("xueyong");
//获取JobExecutionContext中的service对象
try {
SchedulerContext schCtx = context.getScheduler().getContext();
ApplicationContext appCtx = (ApplicationContext)schCtx.get("applicationContext"); //获取Spring中的上下文
LoopbkmkTreeDao loopbkmkTreeDao= (LoopbkmkTreeDao)appCtx.getBean("loopbkmkTreeDao");
System.out.println(projectID+"****777*****"+loopbkmkTreeDao.getAll().size());
} catch (SchedulerException e1) {
e1.printStackTrace();
}
}
};
/*
Cron 表达式包括以下 7 个字段:
* 秒
* 分
* 小时
* 月内日期
* 月
* 周内日期
* 年(可选字段)
特殊字符
Cron 触发器利用一系列特殊字符,如下所示:
●星号(*):可用在所有字段中,表示对应时间域的每一个时刻,例如,*在分钟字段时,表示“每分钟”;
●问号(?):该字符只在日期和星期字段中使用,它通常指定为“无意义的值”,相当于点位符;
●减号(-):表达一个范围,如在小时字段中使用“10-12”,则表示从10到12点,即10,11,12;
●逗号(,):表达一个列表值,如在星期字段中使用“MON,WED,FRI”,则表示星期一,星期三和星期五;
●斜杠(/):x/y表达一个等步长序列,x为起始值,y为增量步长值。如在分钟字段中使用0/15,则表示为0,15,30和45秒,而5/15在分钟字段中表示5,20,35,50,你也可以使用0/y;
●L:该字符只在日期和星期字段中使用,代表“Last”的意思,但它在两个字段中意思不同。L在日期字段中,表示这个月份的最后一天,如一月的31号,非闰年二月的28号;如果L用在星期中,
则表示星期六,等同于7。但是,如果L出现在星期字段里,而且在前面有一个数值X,则表示“这个月的最后X天”,例如,6L表示该月的最后星期五;
●W:该字符只能出现在日期字段里,是对前导日期的修饰,表示离该日期最近的工作日。例如15W表示离该月15号最近的工作日,如果该月15号是星期六,则匹配14号星期五;如果15日是星期日,
则匹配16号星期一;如果15号是星期二,那结果就是15号星期二。但必须注意关联的匹配日期不能够跨月,如你指定1W,如果1号是星期六,结果匹配的是3号星期一,而非上个月最后的那天。W字符串只能指定单一日期,而不能指定日期范围;
●LW组合:在日期字段可以组合使用LW,它的意思是当月的最后一个工作日;
●井号(#):该字符只能在星期字段中使用,表示当月某个工作日。如6#3表示当月的第三个星期五(6表示星期五,#3表示当前的第三个),而4#5表示当月的第五个星期三,假设当月没有第五个星期三,忽略不触发;
● C:该字符只在日期和星期字段中使用,代表“Calendar”的意思。它的意思是计划所关联的日期,如果日期没有被关联,则相当于日历中所有日期。例如5C在日期字段中就相当于日历5日以后的第一天。1C在星期字段中相当于星期日后的第一天。
Cron表达式对特殊字符的大小写不敏感,对代表星期的缩写英文大小写也不敏感。
*/
/*
字段 允许值 允许的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小时 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 或者 JAN-DEC , - * /
星期 1-7 或者 SUN-SAT , - * ? / L C #
年(可选) 留空, 1970-2099 , - * /
表达式意义
"0 0 12 * * ?" 每天中午12点触发
"0 15 10 ? * *" 每天上午10:15触发
"0 15 10 * * ?" 每天上午10:15触发
"0 15 10 * * ? *" 每天上午10:15触发
"0 15 10 * * ? 2005" 2005年的每天上午10:15触发
"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发
"0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发
"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发
"0 15 10 15 * ?" 每月15日上午10:15触发
"0 15 10 L * ?" 每月最后一日的上午10:15触发
"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发
"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发
晚上11点到早上8点之间每两个小时,早上八点
0 23-7/2,8 * * *
每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点
0 11 4 * 1-3
1月1日早上4点
0 4 1 1 *
*/
/*
有些子表达式能包含一些范围或列表
例如:子表达式(天(星期))可以为 “MON-FRI”,“MON,WED,FRI”,“MON-WED,SAT”
“*”字符代表所有可能的值
因此,“*”在子表达式(月)里表示每个月的含义,“*”在子表达式(天(星期))表示星期的每一天
“/”字符用来指定数值的增量
例如:在子表达式(分钟)里的“0/15”表示从第0分钟开始,每15分钟
在子表达式(分钟)里的“3/20”表示从第3分钟开始,每20分钟(它和“3,23,43”)的含义一样
“?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值
当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?”
“L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写
但是它在两个子表达式里的含义是不同的。
在天(月)子表达式中,“L”表示一个月的最后一天
在天(星期)自表达式中,“L”表示一个星期的最后一天,也就是SAT
如果在“L”前有具体的内容,它就具有其他的含义了
例如:“6L”表示这个月的倒数第6天,“FRIL”表示这个月的最一个星期五
注意:在使用“L”参数时,不要指定列表或范围,因为这会导致问题
字段 允许值 允许的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小时 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 或者 JAN-DEC , - * /
星期 1-7 或者 SUN-SAT , - * ? / L C #
年(可选) 留空, 1970-2099 , - * /
*/