转载请注:http://blog.csdn.net/ljqwstc/article/details/78257091
最近接了一个活,需要在项目中添加定时任务。定时任务可以用jdk自带的timer,但是考虑到业务需求,这里可以用小巧灵活非常好用到的Quartz定时管理框架。
写这篇博客主要有两个原因。
第一:是希望自己日后如果有遗忘翻看的时候能想起来怎么操作,所以可能记录的东西不会很全,望谅解,若有写的不对的地方,欢迎拍砖留言。
第二:自己在开始做之前也看了非常多的文章,始终感觉模棱两可,不知怎么下手,在这,我希望有quartz业务需求的朋友看了我的文章后能知道怎么下手,完成业务需求。
废话不多说,下面就简单介绍了如何quartz如何整合spring框架,以及quartz的持久化还有动态添加删除、启动等操作。
org.quartz-scheduler
quartz
2.2.1
org.quartz-scheduler
quartz-jobs
2.2.1
AUTO
${org.quartz.threadPool.class}
${org.quartz.threadPool.threadCount}
${org.quartz.threadPool.threadPriority}
${org.quartz.jobStore.misfireThreshold}
${org.quartz.jobStore.class}
true
15000
1
${org.quartz.jobStore.tablePrefix}
${org.quartz.jobStore.dataSource}
解释:
#============================================================================
# Configure Datasources
#============================================================================
#JDBC驱动
#org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
#org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz?characterEncoding=utf-8
#org.quartz.dataSource.myDS.user = root
#org.quartz.dataSource.myDS.password = root
#org.quartz.dataSource.myDS.maxConnections =5
#集群配置
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount: 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
#============================================================================
# Configure JobStore
#============================================================================
#默认配置,数据保存到内存
#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
#持久化配置
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.useProperties:true
#数据库表前缀
org.quartz.jobStore.tablePrefix:qrtz_
org.quartz.jobStore.dataSource:myDS
#
# Quartz seems to work best with the driver mm.mysql-2.0.7-bin.jar
#
# PLEASE consider using mysql with innodb tables to avoid locking issues
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;
CREATE TABLE QRTZ_JOB_DETAILS
(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(200) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_SIMPLE_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_CRON_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(200) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_BLOB_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_CALENDARS
(
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_FIRED_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_SCHEDULER_STATE
(
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
CREATE TABLE QRTZ_LOCKS
(
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME)
)ENGINE=MyISAM DEFAULT CHARSET=utf8;
commit;
public class ScheduleJob implements Serializable {
private static final long serialVersionUID = -5115028108119830917L;
/**
* 任务名称
*/
private String jobName;
/**
* 任务分组
*/
private String jobGroup;
/**
* 触发器名称(默认和任务名称相同)
*/
private String triggerName;
/**
* 触发器分组(默认和任务分组相同)
*/
private String triggerGroup;
/**
* 任务需要调用的是哪个类的类名
*/
private String className;
/**
* 任务需要调用的是哪个类的方法名
*/
private String methodName;
/**
* 方法所需参数数组
*/
private ArrayList paramArray;
/**
* 任务运行时间表达式
*/
private String cron;
/**
* 任务运行时间(特指只运行一次的任务)
*/
private String runDate;
/**
* 任务描述
*/
private String desc;
getter and setter.....
}
@PersistJobDataAfterExecution
public class QuartzJobFactory implements Job {
/**
* The constant logger.
*/
private static final Logger logger = LoggerFactory.getLogger(Constants.LOG_SYSTEM_RUN);
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
ScheduleJob scheduleJob = (ScheduleJob) jobExecutionContext.getMergedJobDataMap().get("scheduleJob");
//获取service层接口名和接口方法名
String springBeanName = scheduleJob.getClassName();
String methodName = scheduleJob.getMethodName();
//获取参数数组和参数类型数组
ArrayList paramArray = scheduleJob.getParamArray();
Class[] paramType = new Class[paramArray.size()];
for (int i = 0; i < paramArray.size(); i++) {
paramType[i] = paramArray.get(i).getClass();
}
/**
* 反射运行service层的方法
*/
Object bean = SpringContextsUtil.getBean(springBeanName);
Method method = ReflectionUtils.findMethod(bean.getClass(), methodName, paramType);
ReflectionUtils.invokeMethod(method, bean, paramArray.toArray());
logger.info("任务名称 = [" + scheduleJob.getJobName() + "]," +
"任务调用的类=[" + scheduleJob.getClassName() + "]," +
"任务调用的方法=[" + scheduleJob.getMethodName() + "]---->>成功启动运行");
}
}
有状态的两个注解
@Component
public class SpringContextsUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static Object getBean(String beanName) throws BeansException {
return applicationContext.getBean(beanName);
}
public static T getBean(String beanName, Class clazs) {
return applicationContext.getBean(beanName, clazs);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
SpringContextsUtil.applicationContext = applicationContext;
}
}
public interface QuartzProducer {
/**
* 添加简单任务,只运行一次的任务
*
* @param jobName
* @param jobGroup
* @param className
* @param methodName
* @param paramArray
* @param runDateTime 格式:yyyyMMddHHmmss
* @throws SchedulerException
* @throws ParseException
*/
public void addSimpleJob(String jobName, String jobGroup, String className, String methodName, ArrayList paramArray, String runDateTime) throws SchedulerException, ParseException;
/**
* 添加循环任务,特定时间循环运行,例如每个星期3,12点运行等
*
* @param jobName
* @param jobGroup
* @param className
* @param methodName
* @param paramArray
* @param cron
* @throws SchedulerException
*/
public void addCronJob(String jobName, String jobGroup, String className, String methodName, ArrayList paramArray, String cron) throws SchedulerException;
/**
* 修改简单任务,一般指修改运行时间
*
* @param jobName
* @param jobGroup
* @param runDateTime 格式:yyyyMMddHHmmss
*/
public void updateSimpleJob(String jobName, String jobGroup, String runDateTime) throws SchedulerException, ParseException;
/**
* 修改cron任务,一般指修改循环运行时间
*
* @param jobName
* @param jobGroup
* @param cron
*/
public void updateCronJob(String jobName, String jobGroup, String cron) throws SchedulerException;
/**
* 移除任务
*
* @param jobName
* @param jobGroup
*/
public void deleteJob(String jobName, String jobGroup) throws SchedulerException;
/**
* 移除所有任务
*/
public void deleteAll() throws SchedulerException;
/**
* 暂停任务
*
* @param jobName
* @param jobGroup
*/
public void pauseJob(String jobName, String jobGroup) throws SchedulerException;
/**
* 暂停所有任务
*/
public void pauseAll() throws SchedulerException;
/**
* 恢复某个任务
*
* @param jobName
* @param jobGroup
*/
public void resumeJob(String jobName, String jobGroup) throws SchedulerException;
/**
* 恢复所有
*/
public void resumeAll() throws SchedulerException;
/**
* 关闭任务调度器
*/
public void shutDown() throws SchedulerException;
/**
* 开启任务调度器
*/
public void startScheduler() throws SchedulerException;
}
//定义该bean的name为"quartzProducer"
@Service("quartzProducer")
public class QuartzProducerImpl implements QuartzProducer {
//虽然在Spring配置中配置的是SchedulerFactoryBean这个类,但是我们自动转配就写这样,一样是可以使用的
@Autowired
private Scheduler scheduler;
@Override
public void addSimpleJob(String jobName, String jobGroup, String className, String methodName, ArrayList paramArray, String runDateTime) throws SchedulerException, ParseException {
//判断是否已存在相同jobName,jobGroup,若存在则删除
if (scheduler.getJobDetail(JobKey.jobKey(jobName, jobGroup)) != null) {
deleteJob(jobName, jobGroup);
}
JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactory.class).withIdentity(jobName, jobGroup).build();
//任务具体执行的内容封装,返回给job统一入口
ScheduleJob job = new ScheduleJob(jobName, jobGroup, jobName, jobGroup, className, methodName, paramArray, null, runDateTime, null);
//将我自定义的POJO类存放到DataMap中
jobDetail.getJobDataMap().put("scheduleJob", job);
//创建SimpleTrigger,在特定时间仅运行一次
Date runDate = DateUtils.parseDate(runDateTime, DateStyle.YYYYMMDDHHMMSS.getValue());
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger().withIdentity(jobName, jobGroup).
startAt(runDate).build();
scheduler.scheduleJob(jobDetail, trigger);
}
}