quartz是一个提供定时任务的框架。任务可以直接配置在配置文件之中或者数据库里,这种无法修改的任务可以叫做静态任务,而这次写的是怎么创建动态任务,可以在项目运行中对定时任务进行创建、修改、删除等操作。
我这里是基于spring框架搭建的quartz系统。spring配置文件中配置了SchedulerFactoryBean工厂类,用于生成Scheduler对象。
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false">
<property name="dataSource"><!--数据库数据源,这里的任务是配置在数据库中的-->
<ref bean="qrtzDataSource"/>
</property>
<property name="autoStartup" value="true"/> <!--开发人员本机此处默认为false-->
<property name="startupDelay" value="60" />
<property name="applicationContextSchedulerContextKey" value="applicationContext"/>
<property name="configLocation" value="classpath:/spring/quartz.properties"/>
</bean>
表结构都是quartz项目提供的,我用的mysql,选取对应文件即可。
开始coding
1、首先定义一个我们需要的job的信息类
public class QuartzJobBean implements Serializable {
private static final long serialVersionUID = 8426499555496553217L;
public static final String CONCURRENT_IS = "1";
public static final String CONCURRENT_NOT = "0";
public static final String STATUS_NONE = "NONE";
public static final String STATUS_NORMAL = "NORMAL";
public static final String STATUS_PAUSED = "PAUSED";
public static final String STATUS_COMPLETE = "COMPLETE";
public static final String STATUS_ERROR = "ERROR";
public static final String STATUS_BLOCKED = "BLOCKED";
/** 任务id */
private String jobId;
/** 任务名称 */
private String jobName;
/** 任务分组,任务名称+组名称应该是唯一的 */
private String jobGroup;
/** 任务初始状态 0禁用 1启用 2删除*/
private String jobStatus;
/** 任务是否有状态(并发) */
private String isConcurrent = "1";
/** 任务运行时间表达式 */
private String cronExpression;
/** 任务描述 */
private String description;
/** 任务调用类在spring中注册的bean id,如果spingId不为空,则按springId查找 */
private String springId;
/** 任务调用类名,包名+类名,通过类反射调用 ,如果spingId为空,则按jobClass查找 */
private String jobClass;
/** 任务调用的方法名 */
private String methodName;
/** 启动时间 */
private Date startTime;
/** 前一次运行时间 */
private Date previousTime;
/** 下次运行时间 */
private Date nextTime;
//getter、setter方法
2、接下来是核心任务操作类
@Component
public class QuartzJobManage {
private static final Logger logger = LoggerFactory.getLogger(QuartzJobManage.class);
/**
* 添加任务
*
* @param scheduleJob
*/
public void addJob(QuartzJobBean scheduleJob) throws CustomerBizException {
try {
if (scheduleJob == null || !QuartzJobBean.STATUS_NORMAL.equals(scheduleJob.getJobStatus()))
throw new CustomerBizException("添加的任务不能为null并且任务的初始状态必须是[STATUS_NORMAL]");
if (!TaskUtils.isValidExpression(scheduleJob.getCronExpression()))
throw new CustomerBizException("任务名称[" + scheduleJob.getJobName() + "] 任务分组[" + scheduleJob.getJobGroup() + "]的时间表达式错误:" + scheduleJob.getCronExpression());
//SpringContextUtil.getBean("schedulerFactoryBean");就是封装的这个applicationContext.getBean(name);这句代码里面有关于spring IOC的一个机制,如果你实现了spring的FactoryBean<T>接口,那你通过applicationContext.getBean(name)返回的将是getObjectType()方法返回的对象,类型为T,详情可参见spring源码
Scheduler scheduler = (Scheduler) SpringContextUtil.getBean("schedulerFactoryBean");
final TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
Trigger trigger = scheduler.getTrigger(triggerKey);
if (null == trigger){
//这是QuartzJobBean类中定义的真正要执行的任务类
Class<? extends Job> clazz = (Class<? extends Job>) Class.forName(scheduleJob.getJobClass());
final JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup()).build();
jobDetail.getJobDataMap().put("scheduleJob", scheduleJob);
final CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
} else {
// trigger已存在,则更新相应的定时设置
final CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
scheduler.rescheduleJob(triggerKey, trigger);
}
} catch (SchedulerException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/** 暂停任务
* @param scheduleJob
* @return
*/
public void pauseJob(QuartzJobBean scheduleJob){
try {
Scheduler scheduler = (Scheduler) SpringContextUtil.getBean("schedulerFactoryBean");
final JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.pauseJob(jobKey);
} catch (SchedulerException e) {
logger.error("任务暂停失败:", e);
}
}
/**
* 恢复任务
* @param scheduleJob
* @return
*/
public void resumeJob(QuartzJobBean scheduleJob) {
try {
Scheduler scheduler = (Scheduler) SpringContextUtil.getBean("schedulerFactoryBean");
final JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.resumeJob(jobKey);
} catch (SchedulerException e) {
logger.error("任务恢复失败:", e);
}
}
/**
* 删除任务
*/
public void deleteJob(QuartzJobBean scheduleJob){
try {
Scheduler scheduler = (Scheduler) SpringContextUtil.getBean("schedulerFactoryBean");
final JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.deleteJob(jobKey);
} catch (SchedulerException e) {
logger.error("任务名称[" + scheduleJob.getJobName() + "] 分组[" + scheduleJob.getJobGroup() + "] 删除失败!", e);
}
}
/**
* 获取单个任务
* @param jobName
* @param jobGroup
* @return
* @throws SchedulerException
*/
public QuartzJobBean findJob(String jobName, String jobGroup)
{
try
{
QuartzJobBean job = null;
Scheduler scheduler = (Scheduler) SpringContextUtil.getBean("schedulerFactoryBean");
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
CronTrigger trigger = (CronTrigger)scheduler.getTrigger(triggerKey);
JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (trigger != null && jobDetail != null)
{
QuartzJobBean jobExist = (QuartzJobBean)jobDetail.getJobDataMap().get("scheduleJob");
job = new QuartzJobBean();
job.setJobName(jobName);
job.setJobGroup(jobGroup);
job.setDescription("触发器:" + trigger.getKey());
job.setNextTime(trigger.getNextFireTime()); //下次触发时间
job.setPreviousTime(trigger.getPreviousFireTime());//上次触发时间
job.setDescription(jobExist.getDescription());
job.setJobClass(jobExist.getJobClass());
job.setMethodName(jobExist.getMethodName());
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
job.setJobStatus(triggerState.name());
if (trigger instanceof CronTrigger)
{
CronTrigger cronTrigger = (CronTrigger)trigger;
String cronExpression = cronTrigger.getCronExpression();
job.setCronExpression(cronExpression);
}
}
return job;
}
catch (Exception e)
{
logger.error("任务获取失败:", e);
}
return null;
}
}
3、任务执行我用的quartz的Job类,通过集成spring的QuartzJobBean类,他是一个实现了Job接口,完成了任务执行模板(模板模式)的抽象类,我们继承他实现一些自己的逻辑和规则。BaseJob 类也是一个模板,run()方法的实现就是要执行的任务。
@Component
public abstract class BaseJob extends QuartzJobBean{
private static final Logger logger = LoggerFactory.getLogger(BaseJob.class);
/**
* 供实现类运行
* @param context 任务执行上下文
* @throws JobExecutionException 任务执行时异常
*/
protected abstract void run(JobExecutionContext context) throws JobExecutionException;
/**
* @param context 任务执行上下文
* @throws JobExecutionException 任务执行时异常
*/
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try {
run(context);
}
catch (Exception e) {
logger.error(e.toString());
}
finally {
}
}
}
4、任务实现类,举例
public class OrderPayTask extends BaseJob {
@Override
protected void run(JobExecutionContext context) throws JobExecutionException {
//自己的任务实现
}
}
5、任务工具类
public class TaskUtils {
private static final Logger logger = LoggerFactory.getLogger(TaskUtils.class);
/**
* 判断cron时间表达式正确性
* @param cronExpression
* @return
*/
public static boolean isValidExpression(String cronExpression){
CronTriggerImpl trigger = new CronTriggerImpl();
try {
trigger.setCronExpression(cronExpression);
final Date date = trigger.computeFirstFireTime(null);
return date != null && date.after(new Date());
} catch (ParseException e) {
logger.error("时间表达式:" + cronExpression + "错误");
}
return false;
}
}
6、成功之后主要表里的数据
qrtz_job_details
qrtz_job_details
qrtz_triggers
就此完结!