【知识积累】Quartz的使用

一、cron表达式

格式:【秒】 【分】 【时】 【日】 【月】 【周】 【年】

说明必填范围通配符
Y0~59, - * /
Y0~59, - * /
Y0~23, - * /
Y1~31, - * / ? L W
Y1~12 OR JAN~DEC, - * /
Y1~7 OR SUM~SAT, - * / ? L #
Nempty 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");
	}

}

八、运行结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值