diff --git a/README.md b/README.md
index abac556c..278a43fd 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,5 @@
-# xxl-job
-任务调度框架xxl-job
+# 任务调度框架xxl-job
+
+ Scheduler
+ Trigger
+ JobDetail
diff --git a/xxl-job-admin/src/test/java/Test.java b/xxl-job-admin/src/test/java/Test.java
new file mode 100644
index 00000000..74d954e7
--- /dev/null
+++ b/xxl-job-admin/src/test/java/Test.java
@@ -0,0 +1,65 @@
+import java.util.Date;
+import java.util.Timer;
+
+import org.apache.commons.lang.time.FastDateFormat;
+
+
+public class Test {
+
+ static class DemoTimeTask extends java.util.TimerTask {
+ public void run() {
+ System.out.println("run:" + FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss").format(new Date()));
+ }
+ }
+
+ // ??? 某一个时间段内,重复执行
+
+ // runTime:第一次执行时间
+ // delay: 延迟执行的毫秒数,即在delay毫秒之后第一次执行
+ // period:重复执行的时间间隔
+ public static Timer mainTimer;
+ public static void main(String[] args) {
+ // 调度器
+ mainTimer = new Timer();
+ // Demo任务
+ DemoTimeTask timeTask = new DemoTimeTask();
+ System.out.println("now:" + FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss").format(new Date()));
+
+ // 1、在特定时间执行任务,只执行一次
+ //Date runTime = DateUtils.addSeconds(new Date(), 1);
+ //mainTimer.schedule(timeTask, runTime); // runTime
+
+ // 2、在特定时间之后执行任务,只执行一次
+ //long delay = 1000;
+ //mainTimer.schedule(timeTask, delay); // delay/ms
+
+ // 3、指定第一次执行的时间,然后按照间隔时间,重复执行
+ //Date firstTime = DateUtils.addSeconds(new Date(), 1);
+ //long period = 1000;
+ //mainTimer.schedule(timeTask, firstTime, period); // "period/ms" after "firstTime"
+
+ // 4、在特定延迟之后第一次执行,然后按照间隔时间,重复执行
+ //long delay = 1000;
+ //long period = 1000;
+ //mainTimer.schedule(timeTask, delay, period); // "period/ms" after "delay/ms"
+
+ // 5、第一次执行之后,特定频率执行,与3同
+ //Date firstTime = DateUtils.addSeconds(new Date(), 1);
+ //long period = 1000;
+ //mainTimer.scheduleAtFixedRate(timeTask, firstTime, period);
+
+ // 6、在delay毫秒之后第一次执行,后按照特定频率执行
+ long delay = 1000;
+ long period = 1000;
+ mainTimer.scheduleAtFixedRate(timeTask, delay, period);
+ /**
+ * <1>schedule()方法更注重保持间隔时间的稳定:保障每隔period时间可调用一次
+ * <2>scheduleAtFixedRate()方法更注重保持执行频率的稳定:保障多次调用的频率趋近于period时间,如果任务执行时间大于period,会在任务执行之后马上执行下一次任务
+ */
+
+ // Timer注销
+ mainTimer.cancel();
+
+ }
+
+}
diff --git a/xxl-job-demo/pom.xml b/xxl-job-demo/pom.xml
index 4a7bce85..118a158f 100644
--- a/xxl-job-demo/pom.xml
+++ b/xxl-job-demo/pom.xml
@@ -135,6 +135,8 @@
0.0.1-SNAPSHOT
+
+
diff --git a/xxl-job-demo/src/main/java/com/xxl/quartz/DynamicSchedulerUtil.java b/xxl-job-demo/src/main/java/com/xxl/quartz/DynamicSchedulerUtil.java
new file mode 100644
index 00000000..9d086528
--- /dev/null
+++ b/xxl-job-demo/src/main/java/com/xxl/quartz/DynamicSchedulerUtil.java
@@ -0,0 +1,90 @@
+package com.xxl.quartz;
+
+import org.quartz.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.util.Assert;
+
+import java.util.Date;
+
+public final class DynamicSchedulerUtil implements InitializingBean {
+ private static final Logger logger = LoggerFactory.getLogger(DynamicSchedulerUtil.class);
+
+ // Scheduler
+ private static Scheduler scheduler;
+ public static void setScheduler(Scheduler scheduler) {
+ DynamicSchedulerUtil.scheduler = scheduler;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ Assert.notNull(scheduler, "quartz scheduler is null");
+ logger.info(">>>>>>>>> init quartz scheduler success.[{}]", scheduler);
+ }
+
+ // Add 新增
+ public static boolean addJob(JobModel job) throws SchedulerException {
+ final TriggerKey triggerKey = job.getTriggerKey();
+ if (scheduler.checkExists(triggerKey)) {
+ final Trigger trigger = scheduler.getTrigger(triggerKey);
+ logger.info(">>>>>>>>> Already exist trigger [" + trigger + "] by key [" + triggerKey + "] in Scheduler");
+ return false;
+ }
+
+ final CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
+ final CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
+ .withSchedule(cronScheduleBuilder)
+ .build();
+
+ final JobDetail jobDetail = job.getJobDetail();
+ final Date date = scheduler.scheduleJob(jobDetail, cronTrigger);
+
+ logger.debug("Register DynamicJob {} on [{}]", job, date);
+ return true;
+ }
+
+ // Pause 暂停-指定Job
+ public static boolean pauseJob(JobModel existJob) throws SchedulerException {
+ final TriggerKey triggerKey = existJob.getTriggerKey();
+ boolean result = false;
+ if (scheduler.checkExists(triggerKey)) {
+ scheduler.pauseTrigger(triggerKey);
+ result = true;
+ logger.debug("Pause exist DynamicJob {}, triggerKey [{}] successful", existJob, triggerKey);
+ } else {
+ logger.debug("Failed pause exist DynamicJob {}, because not fount triggerKey [{}]", existJob, triggerKey);
+ }
+ return result;
+ }
+
+ // Resume 重启-指定Job
+ public static boolean resumeJob(JobModel existJob) throws SchedulerException {
+ final TriggerKey triggerKey = existJob.getTriggerKey();
+ boolean result = false;
+ if (scheduler.checkExists(triggerKey)) {
+ final CronTrigger newTrigger = existJob.cronTrigger();
+ final Date date = scheduler.rescheduleJob(triggerKey, newTrigger);
+
+ result = true;
+ logger.debug("Resume exist DynamicJob {}, triggerKey [{}] on [{}] successful", existJob, triggerKey, date);
+ } else {
+ logger.debug("Failed resume exist DynamicJob {}, because not fount triggerKey [{}]", existJob, triggerKey);
+ }
+ return result;
+ }
+
+ // Remove exists job 移除-指定Job
+ public static boolean removeJob(JobModel existJob) throws SchedulerException {
+ final TriggerKey triggerKey = existJob.getTriggerKey();
+ boolean result = false;
+ if (scheduler.checkExists(triggerKey)) {
+ result = scheduler.unscheduleJob(triggerKey);
+ }
+
+ logger.debug("Remove DynamicJob {} result [{}]", existJob, result);
+ return result;
+ }
+
+
+}
\ No newline at end of file
diff --git a/xxl-job-demo/src/main/java/com/xxl/quartz/JobModel.java b/xxl-job-demo/src/main/java/com/xxl/quartz/JobModel.java
new file mode 100644
index 00000000..d809e9d5
--- /dev/null
+++ b/xxl-job-demo/src/main/java/com/xxl/quartz/JobModel.java
@@ -0,0 +1,77 @@
+package com.xxl.quartz;
+
+import org.quartz.CronScheduleBuilder;
+import org.quartz.CronTrigger;
+import org.quartz.Job;
+import org.quartz.JobBuilder;
+import org.quartz.JobDataMap;
+import org.quartz.JobDetail;
+import org.quartz.Scheduler;
+import org.quartz.TriggerBuilder;
+import org.quartz.TriggerKey;
+
+/**
+ * 任务model
+ * @author xuxueli 2015-12-1 16:01:19
+ */
+public class JobModel {
+
+ // param
+ private String group;
+ private String name;
+ private String cronExpression;
+ private Class extends Job> jobClass;
+
+ public JobModel(String name, String cronExpression, Class extends Job> jobClass) {
+ this.group = Scheduler.DEFAULT_GROUP;
+ this.name = name;
+ this.cronExpression = cronExpression;
+ this.jobClass = jobClass;
+ }
+
+ public String getGroup() {
+ return group;
+ }
+ public void setGroup(String group) {
+ this.group = group;
+ }
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+ public String getCronExpression() {
+ return cronExpression;
+ }
+ public void setCronExpression(String cronExpression) {
+ this.cronExpression = cronExpression;
+ }
+ public Class extends Job> getJobClass() {
+ return jobClass;
+ }
+ public void setJobClass(Class extends Job> jobClass) {
+ this.jobClass = jobClass;
+ }
+
+ // TriggerKey
+ public TriggerKey getTriggerKey() {
+ return TriggerKey.triggerKey(this.name, this.group);
+ }
+ // JobDetail
+ public JobDetail getJobDetail() {
+ return JobBuilder.newJob(jobClass).withIdentity(this.name, this.group).build();
+ }
+ // JobDataMap.add
+ public JobModel addJobData(String key, Object value) {
+ JobDataMap jobDataMap = this.getJobDetail().getJobDataMap();
+ jobDataMap.put(key, value);
+ return this;
+ }
+ // CronTrigger
+ public CronTrigger cronTrigger() {
+ CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(this.cronExpression);
+ return TriggerBuilder.newTrigger().withIdentity(this.getTriggerKey()).withSchedule(cronScheduleBuilder).build();
+ }
+
+}
\ No newline at end of file
diff --git a/xxl-job-demo/src/main/java/com/xxl/service/impl/TriggerServiceImpl.java b/xxl-job-demo/src/main/java/com/xxl/service/impl/TriggerServiceImpl.java
index e8936414..ec0a2fd8 100644
--- a/xxl-job-demo/src/main/java/com/xxl/service/impl/TriggerServiceImpl.java
+++ b/xxl-job-demo/src/main/java/com/xxl/service/impl/TriggerServiceImpl.java
@@ -1,5 +1,8 @@
package com.xxl.service.impl;
+import java.util.Date;
+
+import org.apache.commons.lang.time.FastDateFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
@@ -19,12 +22,7 @@ public class TriggerServiceImpl implements ITriggerService {
* 全站静态化
*/
public void generateNetHtml() {
- long start = System.currentTimeMillis();
- logger.info("全站静态化... start:{}", start);
-
-
- long end = System.currentTimeMillis();
- logger.info("全站静态化... end:{}, cost:{}", end, end - start);
+ logger.info("全站静态化 run at :{}", FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss").format(new Date()));
}
}
diff --git a/xxl-job-demo/src/main/java/com/xxl/service/job/JobDetailDemo.java b/xxl-job-demo/src/main/java/com/xxl/service/job/JobDetailDemo.java
new file mode 100644
index 00000000..6a493066
--- /dev/null
+++ b/xxl-job-demo/src/main/java/com/xxl/service/job/JobDetailDemo.java
@@ -0,0 +1,21 @@
+package com.xxl.service.job;
+
+import java.util.Date;
+
+import org.apache.commons.lang.time.FastDateFormat;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.scheduling.quartz.QuartzJobBean;
+
+public class JobDetailDemo extends QuartzJobBean {
+ private static Logger logger = LoggerFactory.getLogger(JobDetailDemo.class);
+
+ @Override
+ protected void executeInternal(JobExecutionContext context)
+ throws JobExecutionException {
+ logger.info("全站静态化[DB] run at :{}", FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss").format(new Date()));
+ }
+
+}
diff --git a/xxl-job-demo/src/main/resources/applicationcontext-trigger-db.xml b/xxl-job-demo/src/main/resources/applicationcontext-trigger-db.xml
new file mode 100644
index 00000000..f3ba1019
--- /dev/null
+++ b/xxl-job-demo/src/main/resources/applicationcontext-trigger-db.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/xxl-job-demo/src/main/resources/applicationcontext-trigger.xml b/xxl-job-demo/src/main/resources/applicationcontext-trigger-local.xml
similarity index 92%
rename from xxl-job-demo/src/main/resources/applicationcontext-trigger.xml
rename to xxl-job-demo/src/main/resources/applicationcontext-trigger-local.xml
index 972ebbf6..ffc06c6c 100644
--- a/xxl-job-demo/src/main/resources/applicationcontext-trigger.xml
+++ b/xxl-job-demo/src/main/resources/applicationcontext-trigger-local.xml
@@ -22,7 +22,7 @@
-
+
diff --git a/xxl-job-demo/src/main/resources/quartz.properties b/xxl-job-demo/src/main/resources/quartz.properties
new file mode 100644
index 00000000..a1e68509
--- /dev/null
+++ b/xxl-job-demo/src/main/resources/quartz.properties
@@ -0,0 +1,24 @@
+# Default Properties file for use by StdSchedulerFactory
+# to create a Quartz Scheduler Instance, if a different
+# properties file is not explicitly specified.
+#
+
+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
+
+#org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore
+
+# for cluster
+org.quartz.scheduler.instanceId: AUTO
+org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
+org.quartz.jobStore.isClustered: true
+org.quartz.jobStore.clusterCheckinInterval: 1000
diff --git a/xxl-job-demo/src/test/java/quartz/JunitTest.java b/xxl-job-demo/src/test/java/quartz/JunitTest.java
new file mode 100644
index 00000000..4415a63f
--- /dev/null
+++ b/xxl-job-demo/src/test/java/quartz/JunitTest.java
@@ -0,0 +1,30 @@
+package quartz;
+
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.quartz.SchedulerException;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import com.xxl.quartz.DynamicSchedulerUtil;
+import com.xxl.quartz.JobModel;
+
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration(locations = "classpath*:applicationcontext-*.xml")
+public class JunitTest {
+
+ @Test
+ public void addJob() throws SchedulerException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InterruptedException {
+ boolean ret = DynamicSchedulerUtil.addJob(new JobModel("Jost-job", "0/1 * * * * ?", TestDynamicJob.class));
+ System.out.println(ret);
+ TimeUnit.SECONDS.sleep(30);
+ }
+
+
+
+
+}
diff --git a/xxl-job-demo/src/test/java/quartz/TestDynamicJob.java b/xxl-job-demo/src/test/java/quartz/TestDynamicJob.java
new file mode 100644
index 00000000..8e4f93de
--- /dev/null
+++ b/xxl-job-demo/src/test/java/quartz/TestDynamicJob.java
@@ -0,0 +1,17 @@
+package quartz;
+
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+
+import java.util.Date;
+
+public class TestDynamicJob implements Job {
+
+
+ @Override
+ public void execute(JobExecutionContext context) throws JobExecutionException {
+ final Object mailGuid = context.getMergedJobDataMap().get("mailGuid");
+ System.out.println("[Dynamic-Job] It is " + new Date() + " now, mailGuid=" + mailGuid);
+ }
+}
\ No newline at end of file