超详细 任务调度框架Quartz用法指南( 四 )

ScheduleUtils 调度工具类,这是本篇中最核心的代码:
public class ScheduleUtils {/*** 得到quartz任务类** @param job 执行计划* @return 具体执行任务类*/private static Class<? extends Job> getQuartzJobClass(QuartzJob job) {boolean isConcurrent = "0".equals(job.getConcurrent());return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;}/*** 构建任务触发对象*/public static TriggerKey getTriggerKey(Long jobId, String jobGroup) {return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);}/*** 构建任务键对象*/public static JobKey getJobKey(Long jobId, String jobGroup) {return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);}/*** 创建定时任务*/public static void createScheduleJob(Scheduler scheduler, QuartzJob job) throws Exception {Class<? extends Job> jobClass = getQuartzJobClass(job);// 构建job信息Long jobId = job.getJobId();String jobGroup = job.getJobGroup();JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();// 表达式调度构建器CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);// 按新的cronExpression表达式构建一个新的triggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup)).withSchedule(cronScheduleBuilder).build();// 放入参数,运行时的方法可以获取jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);// 判断是否存在if (scheduler.checkExists(getJobKey(jobId, jobGroup))) {// 防止创建时存在数据问题 先移除,然后在执行创建操作scheduler.deleteJob(getJobKey(jobId, jobGroup));}scheduler.scheduleJob(jobDetail, trigger);// 暂停任务if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) {scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));}}/*** 设置定时任务策略*/public static CronScheduleBuilder handleCronScheduleMisfirePolicy(QuartzJob job, CronScheduleBuilder cb)throws Exception {switch (job.getMisfirePolicy()) {case ScheduleConstants.MISFIRE_DEFAULT:return cb;case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:return cb.withMisfireHandlingInstructionIgnoreMisfires();case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:return cb.withMisfireHandlingInstructionFireAndProceed();case ScheduleConstants.MISFIRE_DO_NOTHING:return cb.withMisfireHandlingInstructionDoNothing();default:throw new Exception("The task misfire policy '" + job.getMisfirePolicy()+ "' cannot be used in cron schedule tasks");}}}这里可以看到,在完成任务与触发器的关联后,如果是暂停状态,会先让调度器停止任务 。
AbstractQuartzJob 抽象任务:
public abstract class AbstractQuartzJob implements Job {private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);/*** 线程本地变量*/private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {QuartzJob job = new QuartzJob();BeanUtils.copyBeanProp(job, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));try {before(context, job);if (job != null) {doExecute(context, job);}after(context, job, null);} catch (Exception e) {log.error("任务执行异常- :", e);after(context, job, e);}}/*** 执行前** @param context 工作执行上下文对象* @param job系统计划任务*/protected void before(JobExecutionContext context, QuartzJob job) {threadLocal.set(new Date());}/*** 执行后** @param context 工作执行上下文对象* @param sysJob系统计划任务*/protected void after(JobExecutionContext context, QuartzJob sysJob, Exception e) {}/*** 执行方法,由子类重载** @param context 工作执行上下文对象* @param job系统计划任务* @throws Exception 执行过程中的异常*/protected abstract void doExecute(JobExecutionContext context, QuartzJob job) throws Exception;}

这个类将原本 execute 方法执行的任务,下放到了子类重载的 doExecute 方法中
【超详细 任务调度框架Quartz用法指南】同时准备实现,分了允许并发和不允许并发,差别就是一个注解:
public class QuartzJobExecution extends AbstractQuartzJob {@Overrideprotected void doExecute(JobExecutionContext context, QuartzJob job) throws Exception {JobInvokeUtil.invokeMethod(job);}}@DisallowConcurrentExecutionpublic class QuartzDisallowConcurrentExecution extends AbstractQuartzJob {@Overrideprotected void doExecute(JobExecutionContext context, QuartzJob job) throws Exception {JobInvokeUtil.invokeMethod(job);}}最后由 JobInvokeUtil 通过反射,进行实际的方法调用:
public class JobInvokeUtil {/*** 执行方法** @param job 系统任务*/public static void invokeMethod(QuartzJob job) throws Exception {String invokeTarget = job.getInvokeTarget();String beanName = getBeanName(invokeTarget);String methodName = getMethodName(invokeTarget);List<Object[]> methodParams = getMethodParams(invokeTarget);if (!isValidClassName(beanName)) {Object bean = SpringUtils.getBean(beanName);invokeMethod(bean, methodName, methodParams);} else {Object bean = Class.forName(beanName).newInstance();invokeMethod(bean, methodName, methodParams);}}/*** 调用任务方法** @param bean目标对象* @param methodName方法名称* @param methodParams 方法参数*/private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,InvocationTargetException {if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0) {Method method = bean.getClass().getDeclaredMethod(methodName, getMethodParamsType(methodParams));method.invoke(bean, getMethodParamsValue(methodParams));} else {Method method = bean.getClass().getDeclaredMethod(methodName);method.invoke(bean);}}/*** 校验是否为为class包名** @param invokeTarget 名称* @return true是 false否*/public static boolean isValidClassName(String invokeTarget) {return StringUtils.countMatches(invokeTarget, ".") > 1;}/*** 获取bean名称** @param invokeTarget 目标字符串* @return bean名称*/public static String getBeanName(String invokeTarget) {String beanName = StringUtils.substringBefore(invokeTarget, "(");return StringUtils.substringBeforeLast(beanName, ".");}/*** 获取bean方法** @param invokeTarget 目标字符串* @return method方法*/public static String getMethodName(String invokeTarget) {String methodName = StringUtils.substringBefore(invokeTarget, "(");return StringUtils.substringAfterLast(methodName, ".");}/*** 获取method方法参数相关列表** @param invokeTarget 目标字符串* @return method方法相关参数列表*/public static List<Object[]> getMethodParams(String invokeTarget) {String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");if (StringUtils.isEmpty(methodStr)) {return null;}String[] methodParams = methodStr.split(",");List<Object[]> classs = new LinkedList<>();for (int i = 0; i < methodParams.length; i++) {String str = StringUtils.trimToEmpty(methodParams[i]);// String字符串类型,包含'if (StringUtils.contains(str, "'")) {classs.add(new Object[]{StringUtils.replace(str, "'", ""), String.class});}// boolean布尔类型,等于true或者falseelse if (StringUtils.equals(str, "true") || StringUtils.equalsIgnoreCase(str, "false")) {classs.add(new Object[]{Boolean.valueOf(str), Boolean.class});}// long长整形,包含Lelse if (StringUtils.containsIgnoreCase(str, "L")) {classs.add(new Object[]{Long.valueOf(StringUtils.replaceIgnoreCase(str, "L", "")), Long.class});}// double浮点类型,包含Delse if (StringUtils.containsIgnoreCase(str, "D")) {classs.add(new Object[]{Double.valueOf(StringUtils.replaceIgnoreCase(str, "D", "")), Double.class});}// 其他类型归类为整形else {classs.add(new Object[]{Integer.valueOf(str), Integer.class});}}return classs;}/*** 获取参数类型** @param methodParams 参数相关列表* @return 参数类型列表*/public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) {Class<?>[] classs = new Class<?>[methodParams.size()];int index = 0;for (Object[] os : methodParams) {classs[index] = (Class<?>) os[1];index++;}return classs;}/*** 获取参数值** @param methodParams 参数相关列表* @return 参数值列表*/public static Object[] getMethodParamsValue(List<Object[]> methodParams) {Object[] classs = new Object[methodParams.size()];int index = 0;for (Object[] os : methodParams) {classs[index] = (Object) os[0];index++;}return classs;}}


推荐阅读