Quartz集成springMVC 的方案二(持久化任务、集群和分布式)
Quartz是一个开放源码项目,专注于任务调度器,提供了极为广泛的特性如持久化任务,集群和分布式任务等。 Quartz核心是调度器,还采用多线程管理。
1.持久化任务:当应用程序停止运行时,所有调度信息不被丢失,当你重新启动时,调度信息还存在,这就是持久化任务。
2.集群和分布式处理:当在集群环境下,当有配置Quartz的多个客户端时(节点),采用Quartz的集群和分布式处理时,我们要了解几点好处 1) 一个节点无法完成的任务,会被集群中拥有相同的任务的节点取代执行。2) Quartz调度是通过触发器的类别来识别不同的任务,在不同的节点定义相同的触发器的类别,这样在集群下能稳定的运行,一个节点无法完成的任务,会被集群中拥有相同的任务的节点取代执行。3)分布式 体现在 当相同的任务定时在一个时间点,在那个时间点,不会被两个节点同时执行。
Quartz的 Task(11 张表)实例化采用数据库存储,基于数据库引擎及 High-Available 的策略(集群的一种策略)自动协调每个节点的 Quartz。
delete from qrtz_fired_triggers;
delete from qrtz_simple_triggers;
delete from qrtz_simprop_triggers;
delete from qrtz_cron_triggers;
delete from qrtz_blob_triggers;
delete from qrtz_triggers;
delete from qrtz_job_details;
delete from qrtz_calendars;
delete from qrtz_paused_trigger_grps;
delete from qrtz_locks;
delete from qrtz_scheduler_state; CREATE TABLE qrtz_job_details
(
SCHED_NAME VARCHAR2(120) NOT NULL,
JOB_NAME VARCHAR2(200) NOT NULL,
JOB_GROUP VARCHAR2(200) NOT NULL,
DESCRIPTION VARCHAR2(250) NULL,
JOB_CLASS_NAME VARCHAR2(250) NOT NULL,
IS_DURABLE VARCHAR2(1) NOT NULL,
IS_NONCONCURRENT VARCHAR2(1) NOT NULL,
IS_UPDATE_DATA VARCHAR2(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR2(1) NOT NULL,
JOB_DATA BLOB NULL,
CONSTRAINT QRTZ_JOB_DETAILS_PK PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE qrtz_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
JOB_NAME VARCHAR2(200) NOT NULL,
JOB_GROUP VARCHAR2(200) NOT NULL,
DESCRIPTION VARCHAR2(250) NULL,
NEXT_FIRE_TIME NUMBER(13) NULL,
PREV_FIRE_TIME NUMBER(13) NULL,
PRIORITY NUMBER(13) NULL,
TRIGGER_STATE VARCHAR2(16) NOT NULL,
TRIGGER_TYPE VARCHAR2(8) NOT NULL,
START_TIME NUMBER(13) NOT NULL,
END_TIME NUMBER(13) NULL,
CALENDAR_NAME VARCHAR2(200) NULL,
MISFIRE_INSTR NUMBER(2) NULL,
JOB_DATA BLOB NULL,
CONSTRAINT QRTZ_TRIGGERS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
CONSTRAINT QRTZ_TRIGGER_TO_JOBS_FK FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)
);
CREATE TABLE qrtz_simple_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
REPEAT_COUNT NUMBER(7) NOT NULL,
REPEAT_INTERVAL NUMBER(12) NOT NULL,
TIMES_TRIGGERED NUMBER(10) NOT NULL,
CONSTRAINT QRTZ_SIMPLE_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
CONSTRAINT QRTZ_SIMPLE_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE qrtz_cron_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
CRON_EXPRESSION VARCHAR2(120) NOT NULL,
TIME_ZONE_ID VARCHAR2(80),
CONSTRAINT QRTZ_CRON_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
CONSTRAINT QRTZ_CRON_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE qrtz_simprop_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
STR_PROP_1 VARCHAR2(512) NULL,
STR_PROP_2 VARCHAR2(512) NULL,
STR_PROP_3 VARCHAR2(512) NULL,
INT_PROP_1 NUMBER(10) NULL,
INT_PROP_2 NUMBER(10) NULL,
LONG_PROP_1 NUMBER(13) NULL,
LONG_PROP_2 NUMBER(13) NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR2(1) NULL,
BOOL_PROP_2 VARCHAR2(1) NULL,
CONSTRAINT QRTZ_SIMPROP_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
CONSTRAINT QRTZ_SIMPROP_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE qrtz_blob_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
BLOB_DATA BLOB NULL,
CONSTRAINT QRTZ_BLOB_TRIG_PK PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
CONSTRAINT QRTZ_BLOB_TRIG_TO_TRIG_FK FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
);
CREATE TABLE qrtz_calendars
(
SCHED_NAME VARCHAR2(120) NOT NULL,
CALENDAR_NAME VARCHAR2(200) NOT NULL,
CALENDAR BLOB NOT NULL,
CONSTRAINT QRTZ_CALENDARS_PK PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)
);
CREATE TABLE qrtz_paused_trigger_grps
(
SCHED_NAME VARCHAR2(120) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
CONSTRAINT QRTZ_PAUSED_TRIG_GRPS_PK PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)
);
CREATE TABLE qrtz_fired_triggers
(
SCHED_NAME VARCHAR2(120) NOT NULL,
ENTRY_ID VARCHAR2(95) NOT NULL,
TRIGGER_NAME VARCHAR2(200) NOT NULL,
TRIGGER_GROUP VARCHAR2(200) NOT NULL,
INSTANCE_NAME VARCHAR2(200) NOT NULL,
FIRED_TIME NUMBER(13) NOT NULL,
SCHED_TIME NUMBER(13) NOT NULL,
PRIORITY NUMBER(13) NOT NULL,
STATE VARCHAR2(16) NOT NULL,
JOB_NAME VARCHAR2(200) NULL,
JOB_GROUP VARCHAR2(200) NULL,
IS_NONCONCURRENT VARCHAR2(1) NULL,
REQUESTS_RECOVERY VARCHAR2(1) NULL,
CONSTRAINT QRTZ_FIRED_TRIGGER_PK PRIMARY KEY (SCHED_NAME,ENTRY_ID)
);
CREATE TABLE qrtz_scheduler_state
(
SCHED_NAME VARCHAR2(120) NOT NULL,
INSTANCE_NAME VARCHAR2(200) NOT NULL,
LAST_CHECKIN_TIME NUMBER(13) NOT NULL,
CHECKIN_INTERVAL NUMBER(13) NOT NULL,
CONSTRAINT QRTZ_SCHEDULER_STATE_PK PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)
);
CREATE TABLE qrtz_locks
(
SCHED_NAME VARCHAR2(120) NOT NULL,
LOCK_NAME VARCHAR2(40) NOT NULL,
CONSTRAINT QRTZ_LOCKS_PK PRIMARY KEY (SCHED_NAME,LOCK_NAME)
); create index idx_qrtz_j_req_recovery on qrtz_job_details(SCHED_NAME,REQUESTS_RECOVERY);
create index idx_qrtz_j_grp on qrtz_job_details(SCHED_NAME,JOB_GROUP); create index idx_qrtz_t_j on qrtz_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);
create index idx_qrtz_t_jg on qrtz_triggers(SCHED_NAME,JOB_GROUP);
create index idx_qrtz_t_c on qrtz_triggers(SCHED_NAME,CALENDAR_NAME);
create index idx_qrtz_t_g on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP);
create index idx_qrtz_t_state on qrtz_triggers(SCHED_NAME,TRIGGER_STATE);
create index idx_qrtz_t_n_state on qrtz_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
create index idx_qrtz_t_n_g_state on qrtz_triggers(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
create index idx_qrtz_t_next_fire_time on qrtz_triggers(SCHED_NAME,NEXT_FIRE_TIME);
create index idx_qrtz_t_nft_st on qrtz_triggers(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
create index idx_qrtz_t_nft_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
create index idx_qrtz_t_nft_st_misfire on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
create index idx_qrtz_t_nft_st_misfire_grp on qrtz_triggers(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); create index idx_qrtz_ft_trig_inst_name on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME);
create index idx_qrtz_ft_inst_job_req_rcvry on qrtz_fired_triggers(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
create index idx_qrtz_ft_j_g on qrtz_fired_triggers(SCHED_NAME,JOB_NAME,JOB_GROUP);
create index idx_qrtz_ft_jg on qrtz_fired_triggers(SCHED_NAME,JOB_GROUP);
create index idx_qrtz_ft_t_g on qrtz_fired_triggers(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
create index idx_qrtz_ft_tg on qrtz_fired_triggers(SCHED_NAME,TRIGGER_GROUP);
我在新建一个张表,为了方便页面能对每个任务进行管理,能对具体某个任务设置开始时间、结束时间、执行的方法、删除等, 如下面图所示:
在这边可以管理开始时间和结束时间和cronExpression值,方便管理对应表的设计:
表都设计好了,整理Quartz集成springMVC的具体的实现。
对Spring的@component 的说明:@component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)
1.举例两个任务具体实现功能,列如quartzJobA和quartzJobB任务要做什么,新建了两个类和方法。
import org.springframework.stereotype.Component; @Component("quartzJobA")
public class Data2ServiceImpl { public void run() {
System.out.println("=============Data2ServiceImpl========="); }
} @Component("quartzJobB")
public class DataServiceImpl { public void test() {
System.out.println("=============DataServiceImpl========="); } }
2.Quartz 调度任务所需的配置文件 quartz-job.properties
#Main Scheduler Settings
org.quartz.scheduler.instanceName=quartzScheduler
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer=true
org.quartz.scheduler.skipUpdateCheck=true
org.quartz.scheduler.batchTriggerAcquisitionMaxCount=100 org.quartz.threadPool.threadCount=10 #Configure JDBC-JobStoreTX
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.dataSource=myDS
org.quartz.jobStore.tablePrefix=QRTZ_
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.acquireTriggersWithinLock=true
org.quartz.jobStore.clusterCheckinInterval = 30000 #Configure DataSources
org.quartz.dataSource.myDS.driver=com.alibaba.druid.proxy.DruidDriver
org.quartz.dataSource.myDS.URL=jdbc:wrap-jdbc:filters=default:name=dragoon:jdbc:oracle:thin:@127.0.0.1:1521:test
org.quartz.dataSource.myDS.user=
org.quartz.dataSource.myDS.password=
org.quartz.dataSource.myDS.maxConnections=5
org.quartz.dataSource.myDS.validationQuery=select 1 from dual
org.quartz.scheduler.instanceName 属性可为任何值,用在 JDBC JobStore 中来唯一标识实例,但是所有集群节点中必须相同
org.quartz.jobStore.class属性为 JobStoreTX,将任务持久化到数据中。因为集群中节点依赖于数据库来传播 Scheduler 实例的状态,你只能在使用 JDBC JobStore 时应用 Quartz 集群。这意味着你必须使用 JobStoreTX 或是 JobStoreCMT 作为 Job 存储;你不能在集群中使用 RAMJobStore
3.实现任务的创建和管理
@Component("schedulerHelper")
public class SchedulerHelper
{ private static final String CONFIG_FILE="quartz-job.properties";
private static final String IDENTITY_JOB_PREFIX="job_";
private static final String IDENTITY_TRIGGER_PREFIX="trigger_"; @Autowired
private JobService jobService;//jobService 这个服务是实现管理任务的页面的服务实现
private Scheduler scheduler; @Autowired
private StartJobSchedulerListener startJobSchedulerListener;//实现自己的Scheduler监听器,程序启动时,任务没创建时就创建 /**
* tomcat一启动时,类实例化时就执行
*/
public void init()
{
try{ // 创建一个定时器工厂
StdSchedulerFactory sf = new StdSchedulerFactory();
//初始化quartz-job.properties配置文件
sf.initialize(Thread.currentThread().getContextClassLoader().getResource(CONFIG_FILE).getFile());
scheduler = sf.getScheduler();
//把jobService放到scheduler上下文,job执行是可以获取并访问。
scheduler.getContext().put(SCHEDULER_KEY_JOBSERVICE,jobService);
startJobSchedulerListener.setSchedulerHelper(this);
//设置自己的监听器
scheduler.getListenerManager().addSchedulerListener(startJobSchedulerListener);
// 启动定时器
scheduler.start();
logger.info("====================job scheduler start");
}catch(SchedulerException e){
logger.error("error",e);
} } /**
* 根据jobentity创建并开始任务
*/
public boolean createAndStartJob(JobEntity job)
{
JobDetail jobDetail=generateJobDetail(job);
Trigger trigger=generateTriggerBuilder(job).build(); try {
scheduler.scheduleJob(jobDetail, trigger);
return true;
} catch (SchedulerException e) {
logger.error("scheduler.scheduleJob",e);
return false;
}
}
/**
* 清除
*/
public void clearAllScheduler()
{
try {
scheduler.clear();
} catch (SchedulerException e) {
logger.error("clearAllScheduler",e);
}
} /**
* 根据jobId和类型删除
*/
public boolean removeJob(Long jobId,String jobType)
{
try {
scheduler.deleteJob(getJobKey(jobId,jobType));
return true;
} catch (SchedulerException e) {
logger.error("removeJob",e);
return false;
}
} /**
* 暂停任务
*/
public boolean pauseJob(Long jobId,String jobType)
{
try {
scheduler.pauseJob(getJobKey(jobId,jobType));
return true;
} catch (SchedulerException e) {
logger.error("resumeJob",e);
return false;
}
} /**
* 马上只执行一次任务
*/
public boolean executeOneceJob(Long jobId,String jobType)
{
try {
Calendar end=Calendar.getInstance();
TriggerBuilder<SimpleTrigger> simpleTriggerBuilder=TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(jobId,jobType))
.forJob(getJobKey(jobId,jobType))
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2));
end.add(Calendar.SECOND, 2);
simpleTriggerBuilder.startAt(end.getTime());
end.add(Calendar.SECOND, 5);
simpleTriggerBuilder.endAt(end.getTime());
JobEntity job=jobService.getJobById(jobId); JobDataMap jobDataMap=new JobDataMap();
jobDataMap.put("jobEntity", job);
simpleTriggerBuilder.usingJobData(jobDataMap);
Trigger trigger=simpleTriggerBuilder.build(); scheduler.scheduleJob(trigger);
return true;
} catch (SchedulerException e) {
logger.error("executeOneceJob",e);
return false;
}
}
/**
* 启动一些scheduler里没有的active的jobDetail
*/
public void createActiveJobFromDB() throws SchedulerException
{
List<JobEntity> jobs=jobService.getActiveJob();
for(JobEntity job:jobs)
{
if(scheduler.getJobDetail(getJobKey(job))==null)
createAndStartJob(job);
}
} /**
* 获得任务的jobKey
*/
public static JobKey getJobKey(Long jobId,String jobType)
{
return new JobKey(IDENTITY_JOB_PREFIX+jobId,IDENTITY_JOB_PREFIX+jobType);
} /**
* 获得任务的jobKey
*/ public static JobKey getJobKey(JobEntity job)
{
return new JobKey(IDENTITY_JOB_PREFIX+job.getJobId(),IDENTITY_JOB_PREFIX+job.getJobType());
} /**
* 获得trigger的triggerkey
*/
public static TriggerKey getTriggerKey(JobEntity job)
{
return new TriggerKey(IDENTITY_TRIGGER_PREFIX+job.getJobId()+"_"+System.currentTimeMillis(), IDENTITY_TRIGGER_PREFIX+job.getJobType());
} /**
* 获得trigger的triggerkey
*/
public static TriggerKey getTriggerKey(Long jobId,String jobType)
{
return new TriggerKey(IDENTITY_TRIGGER_PREFIX+jobId+"_"+System.currentTimeMillis(), IDENTITY_TRIGGER_PREFIX+jobType);
} public static JobDetail generateJobDetail(JobEntity job)
{
JobDataMap jobDataMap=new JobDataMap();
jobDataMap.put("jobEntity", job);
Class<? extends Job> clazz=null;
clazz=BeanJob.class;
return JobBuilder.newJob(clazz)
.withIdentity(getJobKey(job))
.usingJobData(jobDataMap)
.requestRecovery(true).storeDurably(true)
.build();
} /**
* 根据jobEntity获得trigger
*/ public static TriggerBuilder<CronTrigger> generateTriggerBuilder(JobEntity job)
{
TriggerBuilder<CronTrigger> triggerBuilder= TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(job))
.withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpr())
.withMisfireHandlingInstructionDoNothing());
if(job.getSyncBeginTime()!=null)
triggerBuilder.startAt(job.getSyncBeginTime());
else
triggerBuilder.startNow(); if(job.getSyncEndTime()!=null)
triggerBuilder.endAt(job.getSyncEndTime()); return triggerBuilder;
} public static JobService getJobService(JobExecutionContext context)
{
try {
return (JobService) context.getScheduler().getContext().get(SchedulerHelper.SCHEDULER_KEY_JOBSERVICE);
} catch (SchedulerException e) {
logger.error("SchedulerHelper.getJobService",e);
return null;
}
}
@Component("schedulerHelper")
public class SchedulerHelper
{ private static final String CONFIG_FILE="quartz-job.properties";
private static final String IDENTITY_JOB_PREFIX="job_";
private static final String IDENTITY_TRIGGER_PREFIX="trigger_"; @Autowired
private JobService jobService;//jobService 这个服务是实现管理任务的页面的服务实现
private Scheduler scheduler; @Autowired
private StartJobSchedulerListener startJobSchedulerListener;//实现自己的Scheduler监听器,程序启动时,任务没创建时就创建 /**
* tomcat一启动时,类实例化时就执行
*/
public void init()
{
try{ // 创建一个定时器工厂
StdSchedulerFactory sf = new StdSchedulerFactory();
//初始化quartz-job.properties配置文件
sf.initialize(Thread.currentThread().getContextClassLoader().getResource(CONFIG_FILE).getFile());
scheduler = sf.getScheduler();
//把jobService放到scheduler上下文,job执行是可以获取并访问。
scheduler.getContext().put(SCHEDULER_KEY_JOBSERVICE,jobService);
startJobSchedulerListener.setSchedulerHelper(this);
//设置自己的监听器
scheduler.getListenerManager().addSchedulerListener(startJobSchedulerListener);
// 启动定时器
scheduler.start();
logger.info("====================job scheduler start");
}catch(SchedulerException e){
logger.error("error",e);
} } /**
* 根据jobentity创建并开始任务
*/
public boolean createAndStartJob(JobEntity job)
{
JobDetail jobDetail=generateJobDetail(job);
Trigger trigger=generateTriggerBuilder(job).build(); try {
scheduler.scheduleJob(jobDetail, trigger);
return true;
} catch (SchedulerException e) {
logger.error("scheduler.scheduleJob",e);
return false;
}
}
/**
* 清除
*/
public void clearAllScheduler()
{
try {
scheduler.clear();
} catch (SchedulerException e) {
logger.error("clearAllScheduler",e);
}
} /**
* 根据jobId和类型删除
*/
public boolean removeJob(Long jobId,String jobType)
{
try {
scheduler.deleteJob(getJobKey(jobId,jobType));
return true;
} catch (SchedulerException e) {
logger.error("removeJob",e);
return false;
}
} /**
* 暂停任务
*/
public boolean pauseJob(Long jobId,String jobType)
{
try {
scheduler.pauseJob(getJobKey(jobId,jobType));
return true;
} catch (SchedulerException e) {
logger.error("resumeJob",e);
return false;
}
} /**
* 马上只执行一次任务
*/
public boolean executeOneceJob(Long jobId,String jobType)
{
try {
Calendar end=Calendar.getInstance();
TriggerBuilder<SimpleTrigger> simpleTriggerBuilder=TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(jobId,jobType))
.forJob(getJobKey(jobId,jobType))
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2));
end.add(Calendar.SECOND, 2);
simpleTriggerBuilder.startAt(end.getTime());
end.add(Calendar.SECOND, 5);
simpleTriggerBuilder.endAt(end.getTime());
JobEntity job=jobService.getJobById(jobId); JobDataMap jobDataMap=new JobDataMap();
jobDataMap.put("jobEntity", job);
simpleTriggerBuilder.usingJobData(jobDataMap);
Trigger trigger=simpleTriggerBuilder.build(); scheduler.scheduleJob(trigger);
return true;
} catch (SchedulerException e) {
logger.error("executeOneceJob",e);
return false;
}
}
/**
* 启动一些scheduler里没有的active的jobDetail
*/
public void createActiveJobFromDB() throws SchedulerException
{
List<JobEntity> jobs=jobService.getActiveJob();
for(JobEntity job:jobs)
{
if(scheduler.getJobDetail(getJobKey(job))==null)
createAndStartJob(job);
}
} /**
* 获得任务的jobKey
*/
public static JobKey getJobKey(Long jobId,String jobType)
{
return new JobKey(IDENTITY_JOB_PREFIX+jobId,IDENTITY_JOB_PREFIX+jobType);
} /**
* 获得任务的jobKey
*/ public static JobKey getJobKey(JobEntity job)
{
return new JobKey(IDENTITY_JOB_PREFIX+job.getJobId(),IDENTITY_JOB_PREFIX+job.getJobType());
} /**
* 获得trigger的triggerkey
*/
public static TriggerKey getTriggerKey(JobEntity job)
{
return new TriggerKey(IDENTITY_TRIGGER_PREFIX+job.getJobId()+"_"+System.currentTimeMillis(), IDENTITY_TRIGGER_PREFIX+job.getJobType());
} /**
* 获得trigger的triggerkey
*/
public static TriggerKey getTriggerKey(Long jobId,String jobType)
{
return new TriggerKey(IDENTITY_TRIGGER_PREFIX+jobId+"_"+System.currentTimeMillis(), IDENTITY_TRIGGER_PREFIX+jobType);
} public static JobDetail generateJobDetail(JobEntity job)
{
JobDataMap jobDataMap=new JobDataMap();
jobDataMap.put("jobEntity", job);
Class<? extends Job> clazz=null;
clazz=BeanJob.class;
return JobBuilder.newJob(clazz)
.withIdentity(getJobKey(job))
.usingJobData(jobDataMap)
.requestRecovery(true).storeDurably(true)
.build();
} /**
* 根据jobEntity获得trigger
*/ public static TriggerBuilder<CronTrigger> generateTriggerBuilder(JobEntity job)
{
TriggerBuilder<CronTrigger> triggerBuilder= TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(job))
.withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpr())
.withMisfireHandlingInstructionDoNothing());
if(job.getSyncBeginTime()!=null)
triggerBuilder.startAt(job.getSyncBeginTime());
else
triggerBuilder.startNow(); if(job.getSyncEndTime()!=null)
triggerBuilder.endAt(job.getSyncEndTime()); return triggerBuilder;
} public static JobService getJobService(JobExecutionContext context)
{
try {
return (JobService) context.getScheduler().getContext().get(SchedulerHelper.SCHEDULER_KEY_JOBSERVICE);
} catch (SchedulerException e) {
logger.error("SchedulerHelper.getJobService",e);
return null;
}
}
4.实现自己的Scheduler监听器,程序启动时,创建scheduler里没有的active的jobDetail
@Component(value="startJobSchedulerListener")
public class StartJobSchedulerListener extends SchedulerListenerSupport
{
private SchedulerHelper schedulerHelper; @Override
public void schedulerStarted()
{
try {
schedulerHelper.createActiveJobFromDB();
} catch (SchedulerException e) {
logger.error("createActiveJobFromDB",e);
}
} public SchedulerHelper getSchedulerHelper() {
return schedulerHelper;
} public void setSchedulerHelper(SchedulerHelper schedulerHelper) {
this.schedulerHelper = schedulerHelper;
} }
5.实现的是一个job实例对应一个线程并实现页面配置对应的哪个类和方法
public abstract class AbstractEdiJob implements Job
{
protected JobEntity jobEntity;
protected static final Logger logger=LoggerFactory.getLogger(AbstractEdiJob.class);
private Long beginTime; @Override
public void execute(JobExecutionContext context) throws JobExecutionException
{
JobService jobService=SchedulerHelper.getJobService(context);
preExcute(jobService,context);
exeucuteInternal(context);
postExcute(jobService,context);
} abstract public void exeucuteInternal(JobExecutionContext context); public void preExcute(JobService jobService,JobExecutionContext context)
{
beginTime=System.currentTimeMillis();
} public void postExcute(JobService jobService,JobExecutionContext context)
{
//获得最新的jobEntiry
jobEntity=jobService.getJobById(jobEntity.getJobId());
if(jobEntity==null)
{
logger.warn(jobEntity.getJobId()+"job不能存在");
return;
}
if(context.getFireTime()!=null)
jobEntity.setRuntimeLast(context.getFireTime());
if(context.getNextFireTime()!=null)
jobEntity.setRuntimeNext(context.getNextFireTime());
/* else
jobEntity.setJobStatus();*/
Long times=jobEntity.getRunTimes();
jobEntity.setRunTimes((times==null?0l:times)+1);
Long duration=jobEntity.getRunDuration();
jobEntity.setRunDuration((duration==null?0l:duration)+(System.currentTimeMillis()-beginTime));
jobService.updateJob(jobEntity);
//jobEntity这里的改变不能改变JobDetail里的JobEntity,因为生产的job是JobDetail的JobEntity的复制
} public void setJobEntity(JobEntity jobEntity) {
this.jobEntity = jobEntity;
} }
/**
*执行具体类中的方法
**/
public class BeanJob extends AbstractEdiJob
{
private static Logger logger=LoggerFactory.getLogger(BeanJob.class);
@Override
public void exeucuteInternal(JobExecutionContext context)
{
Object obj=SpringContextUtil.getBean(jobEntity.getJobObject());
try {
Method method=obj.getClass().getMethod(jobEntity.getJobMethod());
method.invoke(obj);
} catch (SecurityException e) {
logger.error("error",e);
} catch (NoSuchMethodException e) {
logger.error("error",e);
} catch (IllegalArgumentException e) {
logger.error("error",e);
} catch (IllegalAccessException e) {
logger.error("error",e);
} catch (InvocationTargetException e) {
logger.error("error",e);
}
} }
6.新增一个任务时,数据库就保存对应的触发器,变成持久化任务,如图所示:
1.用StdSchedulerFactory来获取Scheduler的实例,scheduler有启动(start)、中止(stop)和暂停(pause)方法。
2.JobDataMap实例,JobDataMap jobDataMap=new JobDataMap();jobDataMap.put("jobEntity", job);在同一任务的多次执行之间传递数据
3.创建JobDetail实例。JobBuilder.newJob(clazz).withIdentity(getJobKey(job)).usingJobData(jobDataMap).requestRecovery(true).storeDurably(true).build();返回JobDetail实例,newJob(clazz)是要执行特定任务的类;withIdentity(getJobKey(job))是job的任务名和组名;usingJobDatausingJobData(jobDataMap)传输数据;
4.创建Trigger实例。TriggerBuilder<CronTrigger> triggerBuilder= TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(job))
.withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpr())
.withMisfireHandlingInstructionDoNothing());
withIdentity有标示了触发器的名称和组(Quartz调度是通过触发器的类别来识别不同的任务),和withSchedule标示执行的时间表达式
5.最后通过scheduler.scheduleJob()方法调度任务。
Quartz集成springMVC 的方案二(持久化任务、集群和分布式)的更多相关文章
- Quartz集成springMVC 的方案一
Quartz是一个开放源码项目,专注于任务调度器. springMVC 具体的搭建框架就不具体说明,接下来直接描述把Quartz集成到springMVC 框架中. 步骤: 1.引入所需要的jar包 2 ...
- Quartz.net 定时任务之储存与持久化和集群(源码)
一.界面 1.这篇博客不上教程.直接看结果(包括把quartz任务转换成Windows服务) (1).主界面 (2).添加任务(默认执行) (3).编辑(默认开启) (4).关闭和开启 2.代码说明 ...
- Quartz.net 3.x使用总结(二)——Db持久化和集群
上一篇简单介绍了Quartz.net的概念和基本用法,这一篇记录一下Quartz.net通过数据库持久化Trigger和Jobs等数据,并简单配置Quartz.net的集群. 1.JobStore介绍 ...
- t持久化与集群部署开发详解
Quartz.net持久化与集群部署开发详解 序言 我前边有几篇文章有介绍过quartz的基本使用语法与类库.但是他的执行计划都是被写在本地的xml文件中.无法做集群部署,我让它看起来脆弱不堪,那是我 ...
- hadoop(二)hadoop集群的搭建
一.集群环境准备工作 1.修改主机名 在root 账户下 vi /etc/sysconfig/network 或者 sudo vi /etc/sysconfig/network 2.设置系统默认启 ...
- 二、ELKStack集群架构设计
一.ELKStack介绍与入门实践 二.Elasticsearch 集群架构图 服务器配置:Centos6.6 x86_64 CPU:1核心 MEM:2G (做实验,配置比较低一些) 注:这里配置el ...
- MongoDB Sharding(二) -- 搭建分片集群
在上一篇文章中,我们基本了解了分片的概念,本文将着手实践,进行分片集群的搭建 首先我们再来了解一下分片集群的架构,分片集群由三部分构成: mongos:查询路由,在客户端程序和分片之间提供接口.本次实 ...
- redis + 主从 + 持久化 + 分片 + 集群 + spring集成
Redis是一个基于内存的数据库,其不仅读写速度快,每秒可以执行大约110000的写操作,81000的读取操作,而且其支持存储字符串,哈希结构,链表,集合丰富的数据类型.所以得到很多开发者的青睐.加之 ...
- Quartz.net持久化与集群部署开发详解
序言 我前边有几篇文章有介绍过quartz的基本使用语法与类库.但是他的执行计划都是被写在本地的xml文件中.无法做集群部署,我让它看起来脆弱不堪,那是我的罪过. 但是quart.net是经过许多大项 ...
随机推荐
- EF并发性能文章
http://www.cnblogs.com/farb/p/ConcurrencyAndTransctionManagement.html
- Android 监听wifi广播的两种方式
1.XML中声明 <receiver android:name=".NetworkConnectChangedReceiver" > <i ...
- Rational AppScan 扫描大型网站
Rational AppScan 工作原理 Rational AppScan(简称 AppScan)其实是一个产品家族,包括众多的应用安全扫描产品,从开发阶段的源代码扫描的 AppScan sourc ...
- android Settings 解析
1.Settings的主界面的实现: Settings采用了PreferenceActivity和PreferenceFragment结合的实现方式. Settings.java继承自Preferen ...
- 设计模式 - 命令模式(command pattern) 具体解释
命令模式(command pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 命令模式(command pattern) : 将请求封装成对 ...
- Unity用户自定义圆角头像
前天朋友遇到一个这样的需求,而且比较棘手让我帮忙解决.需求就是棋牌类的游戏,玩家的个人资料中包括自己的头像而且可以浏览相册中的图片或者使用相机拍照设置.关于这个问题我也查阅一些资料,由于涉及安卓部分知 ...
- (转)Android 判断用户2G/3G/4G移动数据网络
在做 Android App 的时候,为了给用户省流量,为了不激起用户的愤怒,为了更好的用户体验,是需(要根据用户当前网络情况来做一些调整的,也可以在 App 的设置模块里,让用户自己选择,在 2G ...
- 网页HTML
<head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8&quo ...
- Mac os 上可执行jar包转app方法
此操作可分如下几步: 1:生成jarbao: jar cf myName.jar *.class 2:生成打包所需配置文件:build.xml: <project name="MyPr ...
- memcache运维整理
memcache运维总结 第一部分:memcache安装 1.安装libevent 2.安装memcache 3.安装php的memcache扩展 4.测试 第二部分:memcache客户端操作 1. ...