一、cron表达式
格式:【秒】 【分】 【时】 【日】 【月】 【周】 【年】
说明 | 必填 | 范围 | 通配符 |
秒 | Y | 0~59 | , - * / |
分 | Y | 0~59 | , - * / |
时 | Y | 0~23 | , - * / |
日 | Y | 1~31 | , - * / ? L W |
月 | Y | 1~12 OR JAN~DEC | , - * / |
周 | Y | 1~7 OR SUM~SAT | , - * / ? L # |
年 | N | empty OR 1970~2099 | , - * / |
通配符说明:
,:表示与。例如:在周的位置上配置MON,TUE,WED,则周一、周二和周三触发;
-:表示区间。例如:在小时的位置上配置7-10,则7点、8点、9点、10点会触发;
*:表示所有值。例如:配置在秒的位置上,则每一秒都会触发;
/:表示递增。例如:0/5,则从0开始,每次增加5,0~5~10~15~20……;
?:表示不指定值。只能在日和周的位置上配置。
L:表示最后的意思。只能在日和周的位置上配置。例如:在日的位置上配置,表示当月的最后一天(二月会判断是否是闰年)。在周的位置上,表示周六或者7。
W:表示离指定日期的最近那个工作日(周一~周五)。只能在日和周的位置上配置。例如:日的位置上配置10W,则表示每月的10号最近的那个工作日触发。如果10号是周六,则9号(周五)触发,如果10号是周日,则11号(周一)触发,如果是工作日,则在该日触发。配置1W,则表示每月的1号往后最近的工作日触发。如果1号在周六或者周日,则在下周一触发,如果是工作日,则在该日触发。(不允许区间,只能配置数字)
#:序号,表示每月的第几周星期几。只能在周的位置上配置。例如:0 0 0 5 6#2 *,五月的第二周的星期六触发,0 0 0 6 6#3 *, 六月的第三周的星期六触发。
LW(配合使用):在日的位置上使用LW,则表示本月的最后一个工作日触发。
周的位置上,不区分大小写。
二、web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>web-schedule</display-name>
<!-- spring context -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring/spring-context.xml
</param-value>
</context-param>
三、加载Quartz配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<import resource="classpath:spring/spring-jobs.xml" />
</beans>
四、Quartz配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:jms="http://www.springframework.org/schema/jms"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee
http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<!-- http://ip:port/scheduler/index 访问地址 -->
<!-- 格式:【秒】 【分】 【时】 【日】 【月】 【周】 【年】 -->
<!-- 具体操作的job -->
<bean id="MyTestJobOne" class="com.darren.scheduling.quartz.MyTestJobOne" />
<!-- job的配置 -->
<!-- org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean -->
<bean id="MyTestJobOneDetail"
class="com.darren.scheduling.quartz.MyMethodInvokingJobDetailFactoryBean">
<!-- 指向具体操作的job -->
<property name="targetObject" ref="MyTestJobOne" />
<!-- 指向具体执行的method -->
<property name="targetMethod" value="execute" />
<!-- 是否并发 -->
<property name="concurrent" value="false" />
</bean>
<!-- 调度的配置 -->
<bean id="MyTestJobOneTrigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="MyTestJobOneDetail" />
<!-- cron表达式 -->
<property name="cronExpression" value="0/5 * * * * ?" />
<property name="misfireInstructionName" value="MISFIRE_INSTRUCTION_DO_NOTHING" />
<property name="name" value="One" />
<property name="group" value="Test" />
</bean>
<!-- 具体操作的job -->
<bean id="MyTestJobTwo" class="com.darren.scheduling.quartz.MyTestJobTwo" />
<!-- job的配置 -->
<!-- org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean -->
<bean id="MyTestJobTwoDetail"
class="com.darren.scheduling.quartz.MyMethodInvokingJobDetailFactoryBean">
<!-- 指向具体操作的job -->
<property name="targetObject" ref="MyTestJobTwo" />
<!-- 指向具体执行的method -->
<property name="targetMethod" value="execute" />
<!-- 是否并发 -->
<property name="concurrent" value="false" />
</bean>
<!-- 调度的配置 -->
<bean id="MyTestJobTwoTrigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="MyTestJobTwoDetail" />
<!-- cron表达式 -->
<property name="cronExpression" value="0/2 * * * * ?" />
<property name="misfireInstructionName" value="MISFIRE_INSTRUCTION_DO_NOTHING" />
<property name="name" value="Two" />
<property name="group" value="Test" />
</bean>
<!-- 启动触发器的配置 -->
<bean id="scheduleFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="MyTestJobOneTrigger"/>
<ref bean="MyTestJobTwoTrigger"/>
</list>
</property>
<!-- 是否自动启动 -->
<property name="autoStartup" value="true"/>
</bean>
</beans>
五、重写org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean
package com.darren.scheduling.quartz;
import java.lang.reflect.InvocationTargetException;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
import org.quartz.Scheduler;
import org.quartz.impl.JobDetailImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.support.ArgumentConvertingMethodInvoker;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.JobMethodInvocationFailedException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.MethodInvoker;
public class MyMethodInvokingJobDetailFactoryBean extends ArgumentConvertingMethodInvoker
implements FactoryBean<JobDetail>,
BeanNameAware, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, ApplicationContextAware {
private String name;
private String group = Scheduler.DEFAULT_GROUP;
private boolean concurrent = true;
private String targetBeanName;
private String beanName;
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
private BeanFactory beanFactory;
private JobDetail jobDetail;
@SuppressWarnings("unused")
private ApplicationContext applicationContext;
/**
* Set the name of the job.
* <p>
* Default is the bean name of this FactoryBean.
*/
public void setName(String name) {
this.name = name;
}
/**
* Set the group of the job.
* <p>
* Default is the default group of the Scheduler.
*
* @see org.quartz.Scheduler#DEFAULT_GROUP
*/
public void setGroup(String group) {
this.group = group;
}
/**
* Specify whether or not multiple jobs should be run in a concurrent
* fashion. The behavior when one does not want concurrent jobs to be
* executed is realized through adding the
* {@code @PersistJobDataAfterExecution} and
* {@code @DisallowConcurrentExecution} markers. More information on
* stateful versus stateless jobs can be found <a href=
* "http://www.quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/tutorial-lesson-03"
* > here</a>.
* <p>
* The default setting is to run jobs concurrently.
*/
public void setConcurrent(boolean concurrent) {
this.concurrent = concurrent;
}
/**
* Set the name of the target bean in the Spring BeanFactory.
* <p>
* This is an alternative to specifying {@link #setTargetObject
* "targetObject"}, allowing for non-singleton beans to be invoked. Note
* that specified "targetObject" and {@link #setTargetClass "targetClass"}
* values will override the corresponding effect of this "targetBeanName"
* setting (i.e. statically pre-define the bean type or even the bean
* object).
*/
public void setTargetBeanName(String targetBeanName) {
this.targetBeanName = targetBeanName;
}
@Override
public void setBeanName(String beanName) {
this.beanName = beanName;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
protected Class<?> resolveClassName(String className) throws ClassNotFoundException {
return ClassUtils.forName(className, this.beanClassLoader);
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public void afterPropertiesSet() throws ClassNotFoundException, NoSuchMethodException {
prepare();
String jobName = (this.name != null ? this.name : this.beanName);
Class<?> jobClass = (this.concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);
JobDetailImpl jdi = new JobDetailImpl();
jdi.setName(jobName);
jdi.setGroup(this.group);
jdi.setJobClass((Class) jobClass);
jdi.setDurability(true);
JobDataMap jobDataMap = jdi.getJobDataMap();
jobDataMap.put("methodInvoker", this);
jobDataMap.put("concurrent", concurrent);
this.jobDetail = jdi;
postProcessJobDetail(this.jobDetail);
}
/**
* Callback for post-processing the JobDetail to be exposed by this
* FactoryBean.
* <p>
* The default implementation is empty. Can be overridden in subclasses.
*
* @param jobDetail the JobDetail prepared by this FactoryBean
*/
protected void postProcessJobDetail(JobDetail jobDetail) {
}
/**
* Overridden to support the {@link #setTargetBeanName "targetBeanName"}
* feature.
*/
@Override
public Class<?> getTargetClass() {
Class<?> targetClass = super.getTargetClass();
if (targetClass == null && this.targetBeanName != null) {
Assert.state(this.beanFactory != null, "BeanFactory must be set when using 'targetBeanName'");
targetClass = this.beanFactory.getType(this.targetBeanName);
}
return targetClass;
}
/**
* Overridden to support the {@link #setTargetBeanName "targetBeanName"}
* feature.
*/
@Override
public Object getTargetObject() {
Object targetObject = super.getTargetObject();
if (targetObject == null && this.targetBeanName != null) {
Assert.state(this.beanFactory != null, "BeanFactory must be set when using 'targetBeanName'");
targetObject = this.beanFactory.getBean(this.targetBeanName);
}
return targetObject;
}
@Override
public JobDetail getObject() {
return this.jobDetail;
}
@Override
public Class<? extends JobDetail> getObjectType() {
return (this.jobDetail != null ? this.jobDetail.getClass() : JobDetail.class);
}
@Override
public boolean isSingleton() {
return true;
}
/**
* Quartz Job implementation that invokes a specified method. Automatically
* applied by MethodInvokingJobDetailFactoryBean.
*/
public static class MethodInvokingJob extends QuartzJobBean {
protected static final Logger logger = LoggerFactory.getLogger(MethodInvokingJob.class);
private MethodInvoker methodInvoker;
@SuppressWarnings("unused")
private boolean concurrent;
/**
* Set the MethodInvoker to use.
*/
public void setMethodInvoker(MethodInvoker methodInvoker) {
this.methodInvoker = methodInvoker;
}
public void setConcurrent(boolean concurrent) {
this.concurrent = concurrent;
}
/**
* Invoke the method via the MethodInvoker.
*/
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try {
context.setResult(this.methodInvoker.invoke());
} catch (InvocationTargetException ex) {
if (ex.getTargetException() instanceof JobExecutionException) {
throw (JobExecutionException) ex.getTargetException();
} else {
throw new JobMethodInvocationFailedException(this.methodInvoker, ex.getTargetException());
}
} catch (Exception ex) {
throw new JobMethodInvocationFailedException(this.methodInvoker, ex);
}
}
}
/**
* Extension of the MethodInvokingJob, implementing the StatefulJob
* interface. Quartz checks whether or not jobs are stateful and if so,
* won't let jobs interfere with each other.
*/
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public static class StatefulMethodInvokingJob extends MethodInvokingJob {
}
@Override
public void setApplicationContext(ApplicationContext applicationContext){
this.applicationContext = applicationContext;
}
}
六、MyTestJobOne
package com.darren.scheduling.quartz;
public class MyTestJobOne {
public void execute() {
System.out.println("MyTestJobOne");
}
}
七、MyTestJobTwo
package com.darren.scheduling.quartz;
public class MyTestJobTwo {
public void execute() {
System.out.println("MyTestJobTwo");
}
}
八、运行结果