有时,我们需要程序进行不同的调度进行执行,比如每天早晨10点执行、每隔10分钟执行一次、今晚20:00执行等。
所以,此处通过开源的作业调度框架Quart快速完成任务调度的工作.
基本原理:1、创建调度工厂(); //工厂模式
2、根据工厂取得调度器实例(); //工厂模式
3、Builder模式构建子组件<Job,Trigger> // builder模式, 如JobBuilder、TriggerBuilder、DateBuilder
4、通过调度器组装子组件 调度器.组装<子组件1,子组件2...> //工厂模式
5、调度器.start(); //工厂模式
核心算法:
QuartzJobBean.java
public class QuartzJobBean implements StatefulJob {
private Log log = LogFactory.getLog(QuartzJobBean.class);
public static final String TARGET_CLASS = "class";
public static final String TARGET_METHOD = "method";
public static final String TARGET_ARGUMENTS = "arguments";
private static ApplicationContext ac;
public static void setAc(ApplicationContext ac) {
QuartzJobBean.ac = ac;
}
public static ApplicationContext getApplicationContext() {
return ac;
}
/**
* 通过类名和方法名去获取目标对象,再通过反射执行
* 类名和方法名保存在jobDetail中
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
String targetClass = (String) context.getMergedJobDataMap().get(TARGET_CLASS);
String targetMethod = (String) context.getMergedJobDataMap().get(TARGET_METHOD);
String methodArgs = (String) context.getMergedJobDataMap().get(TARGET_ARGUMENTS);
if (StringUtils.isEmpty(targetClass) || StringUtils.isEmpty(targetMethod))
return;
Object[] args = null;
if (!StringUtils.isEmpty(methodArgs)) {
methodArgs = methodArgs + " ";
String[] argString = methodArgs.split("#&");
args = new Object[argString.length];
for (int i = 0; i < argString.length; i++) {
args[i] = argString[i].trim();
}
}
JobContext.className.set(targetClass);
JobContext.methodName.set(targetMethod);
JobContext.argStr.set(methodArgs);
CacheContext.method.set(targetClass + "_" + targetMethod);
long startTime = System.currentTimeMillis();
try {
Object target = ac.getBean(targetClass);
if (null != target) {
Class tc = target.getClass();
Class[] parameterType = null;
if (args != null) {
parameterType = new Class[args.length];
for (int i = 0; i < args.length; i++) {
parameterType[i] = String.class;
}
}
Method method = tc.getDeclaredMethod(targetMethod, parameterType);
if (null != method) {
method.invoke(target, args);
}
}
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new JobExecutionException(e);
}
log.error("[QuartzJobBean]" + targetClass + ", " + targetMethod + ", " + methodArgs
+ ", used time " + (System.currentTimeMillis() - startTime));
}
}
BasicScheduler.java
public class BasicScheduler extends ApplicationObjectSupport implements
ApplicationListener<ApplicationEvent> {
private final static Log log = LogFactory.getLog(BasicScheduler.class);
static SchedulerFactory sf = new StdSchedulerFactory();
private static Scheduler scheduler;
{
try {
scheduler = sf.getScheduler();
} catch (SchedulerException e) {
}
}
@Resource
private BasicJobConfig basicJobConfig;
@Resource
private BasicQuartzJobDAO basicQuartzJobDAO;
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
ContextRefreshedEvent cre = (ContextRefreshedEvent) event;
log.error("BasicScheduler Start. " + cre.getApplicationContext().getDisplayName());
if (cre.getApplicationContext().getParent() == null
&& cre.getApplicationContext().getDisplayName()
.equalsIgnoreCase("Root WebApplicationContext")) {
ApplicationContext ac = getApplicationContext();
QuartzJobBean.setAc(ac);
}
}
}
/**
* Quartz启动任务
* @param basicQuartzJob
* @throws Exception
*/
private void enable(BasicQuartzJob basicQuartzJob) throws Exception {
CronTrigger trigger =
(CronTrigger) scheduler.getTrigger(basicQuartzJob.getTriggerName(),
basicQuartzJob.getJobGroup());
if (null == trigger) {
JobDetail jobDetail =
new JobDetail(basicQuartzJob.getJobName(), basicQuartzJob.getJobGroup(),
QuartzJobBean.class);
jobDetail.getJobDataMap().put(QuartzJobBean.TARGET_CLASS, basicQuartzJob.getJobClass());
jobDetail.getJobDataMap().put(QuartzJobBean.TARGET_METHOD,
basicQuartzJob.getJobMethod());
jobDetail.getJobDataMap().put(QuartzJobBean.TARGET_ARGUMENTS,
basicQuartzJob.getJobArguments());
trigger =
new CronTrigger(basicQuartzJob.getTriggerName(), basicQuartzJob.getJobGroup(),
basicQuartzJob.getCronExpression());
scheduler.scheduleJob(jobDetail, trigger);
/**
* trigger 有name jobName group jobGroup 如果没有设置jobName,则在调度时会用jobDetail的name和group赋值
* trigger的jobName和jobGroup,必须和jobDetail的保持一致
*/
if (log.isInfoEnabled()) {
log.info(basicQuartzJob.toString() + ", add new.");
}
} else {
trigger.setCronExpression(basicQuartzJob.getCronExpression());
scheduler.rescheduleJob(trigger.getName(), trigger.getGroup(), trigger);
if (log.isInfoEnabled()) {
log.info(basicQuartzJob.toString() + ", modify exist.");
}
}
}
}
job_class为任务类在spring中的bean对象名称
job_method为任务方法的名称
job_name为任务的名称
job_group对于同一个名称的任务在一个任务组中只能有一个任务实例,因此如果实现同一个任务,依据参数不同执行多个任务实例,请设置为不同的任务组
需要修改的一般仅限于job_arguments和cron_expression
job_arguments代表的是任务的参数,如果有多个参数请用#&分开
cron_expression是用来指定何时执行任务。
一个cron表达式有至少6个(也可能是7个)由空格分隔的时间元素。从左至右,这些元素的定义如下:
1.秒(0–59)
2.分钟(0–59)
3.小时(0–23)
4.月份中的日期(1–31)
5.月份(1–12或JAN–DEC)
6.星期中的日期(1–7或SUN–SAT)
7.年份(1970–2099)
表 达 式 | 意 义 |
0 0/10 * * * ? | 每隔10分钟一次 |
0 0 10,14,16 * * ? | 每天上午10点,下午2点和下午4点 |
0 0,15,30,45 * 1-10 * ? | 每月前10天每隔15分钟 |
30 0 0 1 1 ? 2012 | 在2012年1月1日午夜过30秒时 |
0 0 8-5 ? * MON-FRI | 每个工作日的工作时间 |