注: 该代码为玛雅妞代码改动而成, 只是JFinal2.2的logger改成了Log。 使用方法 : http://my.oschina.net/myaniu/blog/488386 package com.jfinal.test; import com.jfinal.plugin.IPlugin; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import com.jfinal.kit.Prop; import com.jfinal.kit.PropKit; import com.jfinal.kit.StrKit; import com.jfinal.log.Log; import it.sauronsoftware.cron4j.Scheduler; public class SchedulerPlugin implements IPlugin{ private static Log LOG = Log.getLog("SchedulerPlugin"); /** * cron调度器 */ private final Scheduler cronScheduler = new Scheduler(); /** * ScheduledThreadPoolExecutor调度器 */ private final ScheduledThreadPoolExecutor taskScheduler; /** * 调度任务配置文件 */ private final String jobConfigFile; /** * <p> * Title: SchedulerPlugin * </p> * <p> * Description: 构造函数(线程池依据系统核心数自动设定) * </p> * * @since V1.0.0 */ public SchedulerPlugin() { this(getBestPoolSize(), null); } /** * <p> * Title: SchedulerPlugin * </p> * <p> * Description: 构造函数(指定调度线程池大小) * </p> * * @param scheduledThreadPoolSize * 调度线程池大小 * @since V1.3.0 */ public SchedulerPlugin(int scheduledThreadPoolSize) { this(scheduledThreadPoolSize, null); } /** * <p> * Title: SchedulerPlugin * </p> * <p> * Description: 构造函数(指定调度任务配置文件,线程池依据系统核心数自动设定) * </p> * * @param jobConfigFile * 调度任务配置文件 * @since V1.0.0 */ public SchedulerPlugin(String jobConfigFile) { this(getBestPoolSize(), jobConfigFile); } /** * <p> * Title: SchedulerPlugin * </p> * <p> * Description: 构造函数(指定调度线程池大小和调度任务配置文件) * </p> * * @param scheduledThreadPoolSize * 调度线程池大小 * @param jobConfigFile * 调度任务配置文件 * @since V1.3.0 */ public SchedulerPlugin(int scheduledThreadPoolSize, String jobConfigFile) { this.jobConfigFile = jobConfigFile; this.taskScheduler = new ScheduledThreadPoolExecutor(scheduledThreadPoolSize); } /** * @Title: cronSchedule * @Description: 添加基于Linux下的crontab表达式的调度任务(Runnable) * @param task * 定期执行的任务(Runnable) * @param cronExpression * cron调度表达式 * @since V1.0.0 */ public void cronSchedule(Runnable task, String cronExpression) { this.cronScheduler.schedule(cronExpression, task); } /** * @Title: fixedRateSchedule * @Description: 立即启动,并以固定的频率来运行任务。后续任务的启动时间不受前次任务延时影响(并行)。 * @param task * 定期执行的任务 * @param periodSeconds * 每次执行任务的间隔时间(单位秒) * @return * @since V1.0.0 */ public ScheduledFuture<?> fixedRateSchedule(Runnable task, int periodSeconds) { return taskScheduler.scheduleAtFixedRate(task, 0, periodSeconds, TimeUnit.SECONDS); } /** * @Title: fixedDelaySchedule * @Description: 立即启动,两次任务间保持固定的时间间隔(任务串行执行,前一个结束之后间隔固定时间后一个才会启动) * @param task * 定期执行的任务 * @param periodSeconds * 每次执行任务的间隔时间(单位秒) * @return * @since V1.0.0 */ public ScheduledFuture<?> fixedDelaySchedule(Runnable task, int periodSeconds) { return taskScheduler.scheduleWithFixedDelay(task, 0, periodSeconds, TimeUnit.SECONDS); } @Override public boolean start() { if (this.jobConfigFile != null) { // 任务配置文件非空,从配置文件汇总加载任务 loadJobsFromConfigFile(); } this.cronScheduler.setDaemon(true); this.cronScheduler.start(); LOG.info("SchedulerPlugin is started"); return true; } @Override public boolean stop() { this.cronScheduler.stop(); this.taskScheduler.shutdown(); LOG.info("SchedulerPlugin is stopped"); return true; } /** * @Title: loadJobsFromConfigFile * @Description: 从配置文件汇总加载任务 * @since V1.0.0 */ private void loadJobsFromConfigFile() { // 获取job配置文件 Prop jobProp = PropKit.use(this.jobConfigFile); // 获得所有任务名 Set<String> jobNames = this.getJobNamesFromProp(jobProp); // 逐个加载任务 for (String jobName : jobNames) { loadJob(jobProp, jobName); } } /** * @Title: loadJob * @Description: 加载一个任务 * @param jobProp * job配置 * @param jobName * job名 * @since V1.0.0 */ private void loadJob(Prop jobProp, String jobName) { // 任务开关,默认开启 Boolean enable = jobProp.getBoolean(jobName + ".enable", Boolean.TRUE); // 任务被禁用,直接返回 if (!enable) { return; } // 创建要执行的任务 Runnable task = createTask(jobName, jobProp.get(jobName + ".class")); // 任务类型 String taskType = jobProp.get(jobName + ".type"); if (StrKit.isBlank(taskType)) { throw new RuntimeException("Please set " + jobName + ".type"); } // 任务表达式 String expr = jobProp.get(jobName + ".expr"); if (StrKit.isBlank(expr)) { throw new RuntimeException("Please set " + jobName + ".expr"); } // 依据任务类型,开始调度任务 scheduleJobByType(jobName, taskType, expr, task); LOG.info("--------load job: " + jobName + " successfully--------"); LOG.info("class: " + jobProp.get(jobName + ".class")); LOG.info("type : " + taskType); LOG.info("expr : " + expr); LOG.info("----------------"); } /** * @Title: scheduleJobByType * @Description: 依据任务类型,开始调度任务 * @param jobName * 任务名 * @param taskType * 任务类型 * @param expr * 调度表达式 * @param task * 执行的任务 * @since V1.0.0 */ private void scheduleJobByType(String jobName, String taskType, String expr, Runnable task) { if ("cron".equals(taskType)) { this.cronSchedule(task, expr); } else if ("fixedRate".equals(taskType)) { int periodSeconds = 0; try { periodSeconds = Integer.parseInt(expr); } catch (NumberFormatException e) { throw new RuntimeException(jobName + ".expr must be a number"); } this.fixedRateSchedule(task, periodSeconds); } else if ("fixedDelay".equals(taskType)) { int periodSeconds = 0; try { periodSeconds = Integer.parseInt(expr); } catch (NumberFormatException e) { throw new RuntimeException(jobName + ".expr must be a number"); } this.fixedDelaySchedule(task, periodSeconds); } else { throw new RuntimeException("Please set " + jobName + ".type to cron/fixedRate/fixedDelay"); } } /** * @Title: createTask * @Description: 创建任务 * @param jobName * 任务名 * @param taskClassName * 任务类名 * @return Runnable对象 * @since V1.0.0 */ private Runnable createTask(String jobName, String taskClassName) { if (taskClassName == null) { throw new RuntimeException("Please set " + jobName + ".className"); } Object temp = null; try { temp = Class.forName(taskClassName).newInstance(); } catch (Exception e) { throw new RuntimeException("Can not create instance of class: " + taskClassName, e); } Runnable task = null; if (temp instanceof Runnable) { task = (Runnable) temp; } else { throw new RuntimeException("Can not create instance of class: " + taskClassName + ". this class must implements Runnable interface"); } return task; } /** * @Title: getJobNamesFromProp * @Description: 获得所有任务名 * @param jobProp * job配置 * @return 任务名集合 * @since V1.0.0 */ private Set<String> getJobNamesFromProp(Prop jobProp) { Map<String, Boolean> jobNames = new HashMap<String, Boolean>(); for (Object item : jobProp.getProperties().keySet()) { String fullKeyName = item.toString(); // 获得job名 String jobName = fullKeyName.substring(0, fullKeyName.indexOf(".")); jobNames.put(jobName, Boolean.TRUE); } return jobNames.keySet(); } /** * @Title: getBestPoolSize * @Description: 获得调度线程池大小 * @return * @since V1.0.0 */ private static int getBestPoolSize() { try { final int cores = Runtime.getRuntime().availableProcessors(); // 每个核有8个调度线程 return cores * 8; } catch (Throwable e) { return 8; } } }