master
xueli.xue 9 years ago
parent 08950b0b6c
commit 328f98a252
  1. 7
      README.md
  2. 65
      xxl-job-admin/src/test/java/Test.java
  3. 2
      xxl-job-demo/pom.xml
  4. 90
      xxl-job-demo/src/main/java/com/xxl/quartz/DynamicSchedulerUtil.java
  5. 77
      xxl-job-demo/src/main/java/com/xxl/quartz/JobModel.java
  6. 10
      xxl-job-demo/src/main/java/com/xxl/service/impl/TriggerServiceImpl.java
  7. 21
      xxl-job-demo/src/main/java/com/xxl/service/job/JobDetailDemo.java
  8. 46
      xxl-job-demo/src/main/resources/applicationcontext-trigger-db.xml
  9. 2
      xxl-job-demo/src/main/resources/applicationcontext-trigger-local.xml
  10. 24
      xxl-job-demo/src/main/resources/quartz.properties
  11. 30
      xxl-job-demo/src/test/java/quartz/JunitTest.java
  12. 17
      xxl-job-demo/src/test/java/quartz/TestDynamicJob.java

@ -1,2 +1,5 @@
# xxl-job
任务调度框架xxl-job
# 任务调度框架xxl-job
Scheduler
Trigger
JobDetail

@ -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();
}
}

@ -135,6 +135,8 @@
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>

@ -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;
}
}

@ -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();
}
}

@ -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()));
}
}

@ -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()));
}
}

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<!-- Job trigger -->
<bean id="job02Trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" >
<bean class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.xxl.service.job.JobDetailDemo"/>
<property name="jobDataAsMap">
<map>
<!-- <entry key="xxService" value-ref="xxService" /> -->
</map>
</property>
<property name="durability" value="true" />
</bean>
</property>
<property name="cronExpression" value="0/3 * * * * ? *" />
</bean>
<!-- Job信息会被上报并持久化到mysql中,多个集群节点中竞争Job锁,只会有一台执行 -->
<bean id="quartzScheduler" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="autoStartup" value="true" />
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<property name="configLocation" value="classpath:quartz.properties"/>
<property name="triggers">
<list>
<!-- <ref bean="job02Trigger" /> -->
</list>
</property>
</bean>
<!-- 调度器 -->
<bean id="dynamicSchedulerUtil" class="com.xxl.quartz.DynamicSchedulerUtil">
<property name="scheduler" ref="quartzScheduler"/>
</bean>
</beans>

@ -22,7 +22,7 @@
<property name="cronExpression" value="0/3 * * * * ? *" />
</bean>
<!-- 启动触发器的配置开始 -->
<!-- Job被加载到内存中,每个集群节点相互独立,都会执行该任务 -->
<bean name="startQuertz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>

@ -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

@ -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);
}
}

@ -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);
}
}
Loading…
Cancel
Save