您的位置:首页 > 编程语言 > Java开发

Spring-定时任务之Quartz

2016-02-02 21:06 369 查看
最近的项目中,使用了定时任务。网上搜索了很多关于定时任务的解决方案,大概总结一下有以下几种解决思路1)java.util.Timer;2)Quartz;3)Spring3.0以后自带的task。本次项目解决方案采用的是Quartz来实现定时任务。

在 项目的过程中,期初需要的需求很简单(完成定时请求服务端的数据),采用了Quartz的配置方式,简单的配置后即可完成定时的任务,这算是静态定时任务。不久后,需要定时任务由用户自己配置,如配置任务执行周期、任务内容、开启/运行任务、添加/删除任务等,在网上寻找新的解决方法,最终选择采用了quartz的编程实现方式。

下面分别介绍这两种实现不同需求的定时任务的实现过程(原理性以后补充)。

方法一、配置实现

主要步骤:

a)在Spring.xml中,调度器里添加了两个触发器simpleTrigger和cronTrigger,前者是简单定时触发,后者采用了cron表达式。在类loopTask中,实现了两个定时触发器响应方法。

<bean id="loopTask" class="xxxxxx.MyLoopTask"/>
<bean id="loopCreateTable" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="loopTask" />
<property name="targetMethod" value="loopCreateDataTable" />
</bean>
<bean id="loopCreateTable" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="loopTask" />
<property name="targetMethod" value="loopCreateDataTable" />
</bean>
<bean id="loopOriginalData" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="loopTask" />
<property name="targetMethod" value="loopOriginalData" />
</bean>
<bean id="simpleTrigger"
class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="loopOriginalData" />
<property name="startDelay" value="10000" />
<property name="repeatInterval" value="${httpconn1.period}" />
</bean>
<bean id="cronTrigger" class="org.springframework.scheduling.qu
4000
artz.CronTriggerFactoryBean">
<property name="jobDetail" ref="loopCreateTable" />
<property name="cronExpression" value="0 0 * * * ?" />
</bean>


b)MyLookTask类,在该类中配置了服务类AService,可以在定时任务方法中使用(强调这个是因为在第二个动态定时任务中失效。)

public class MyLoopTask {
@Resource(name="AService")
private AService aservice;

public void loopCreateDataTable()
{
//使用aservice
}
public void loopOriginalData() {
//使用aservice

}


方法二、编码实现

编码实现,即在程序中实现动态定时任务,这里主要采用了几个工具类来完成定时任务:

MyJob类:实现了org.quartz.Job接口;

QuartUntils类:调度器工具类;

DutiesAgency类:在项目中,在定时任务调用的方法里无法使用服务类(由注解或配置注入的服务类),所以添加了一个代理任务,该代理任务包含了具体任务和被具体任务调用的服务。

具体实现类如下:

public class QuartzUntils {
private Logger log = null;
private Scheduler scheduler = null;
public static final String DATA_KEY = "STATE_DATA";

public QuartzUntils() {
try {
log = org.apache.logging.log4j.LogManager.getLogger();
scheduler = new StdSchedulerFactory().getScheduler();
log.info("初始化调度器 ");
} catch (SchedulerException ex) {
log.error("初始化调度器=> [失败]:" + ex.getLocalizedMessage());
}
}
public void addJob(DutiesAgency da) {
try {
//构造任务
JobDetail job = newJob(MyJob.class)
.withIdentity(da.getCrontabMangeEntity().getJobName(), da.getCrontabMangeEntity().getJobGroup())
.build();
job.getJobDataMap().put("DutiesAgency",da);
//构造任务触发器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(da.getCrontabMangeEntity().getCronExpression());
Trigger trg = newTrigger()
.withIdentity(da.getCrontabMangeEntity().getJobName(), da.getCrontabMangeEntity().getJobName())
.withSchedule(scheduleBuilder)
.build();
//将作业添加到调度器
scheduler.scheduleJob(job, trg);
log.info("创建作业=> [作业名称:" +da.getCrontabMangeEntity().getJobName() + " 作业组:" + da.getCrontabMangeEntity().getJobName() + "] ");
} catch (SchedulerException e) {
e.printStackTrace();
}
}
public void removeJob(String name, String group) {
try {
TriggerKey tk = TriggerKey.triggerKey(name, group);
scheduler.pauseTrigger(tk);//停止触发器
scheduler.unscheduleJob(tk);//移除触发器
JobKey jobKey = JobKey.jobKey(name, group);
scheduler.deleteJob(jobKey);//删除作业
log.info("删除作业=> [作业名称:" + name + " 作业组:" + group + "] ");
} catch (SchedulerException e) {
e.printStackTrace();
log.error("删除作业=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]");
}
}
public void pauseJob(String name, String group) {
try {
JobKey jobKey = JobKey.jobKey(name, group);
scheduler.pauseJob(jobKey);
log.info("暂停作业=> [作业名称:" + name + " 作业组:" + group + "] ");
} catch (SchedulerException e) {
e.printStackTrace();
log.error("暂停作业=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]");
}
}
public void resumeJob(String name, String group) {
try {
JobKey jobKey = JobKey.jobKey(name, group);
scheduler.resumeJob(jobKey);
log.info("恢复作业=> [作业名称:" + name + " 作业组:" + group + "] ");
} catch (SchedulerException e) {
e.printStackTrace();
log.error("恢复作业=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]");
}
}
public void modifyTime(String name, String group, String cronExpression) {
try {
TriggerKey tk = TriggerKey.triggerKey(name, group);
//构造任务触发器
Trigger trg = newTrigger()
.withIdentity(name, group)
.withSchedule(cronSchedule(cronExpression))
.build();
scheduler.rescheduleJob(tk, trg);
log.info("修改作业触发时间=> [作业名称:" + name + " 作业组:" + group + "] ");
} catch (SchedulerException e) {
e.printStackTrace();
log.error("修改作业触发时间=> [作业名称:" + name + " 作业组:" + group + "]=> [失败]");
}
}
public void start() {
try {
scheduler.start();
System.out.println("启动调度器");
log.info("启动调度器 ");
} catch (SchedulerException e) {
e.printStackTrace();
log.error("启动调度器=> [失败]");
}
}
public void shutdown() {
try {
scheduler.shutdown();
log.info("停止调度器 ");
} catch (SchedulerException e) {
e.printStackTrace();
log.error("停止调度器=> [失败]");
}
}
public static void main(String[] args) {
QuartzUntils quartzUntils=new QuartzUntils();
ScheduleJob job = new ScheduleJob();
job.setJobId("10001");
job.setJobName("data_import");
job.setJobGroup("dataWork");
job.setCronExpression("0/5 * * * * ?");
quartzUntils.addJob(job);
quartzUntils.start();*/
}

public class MyJob implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("定时任务开始...");
DutiesAgency da = (DutiesAgency) context.getMergedJobDataMap().get("DutiesAgency");
da.getOriginalDataService().dataDistribution(da.getCrontabMangeEntity());
}
}


public class DutiesAgency {
private CrontabMangeEntity crontabMangeEntity;
private OriginalDataService originalDataService;
public CrontabMangeEntity getCrontabMangeEntity() {
return crontabMangeEntity;
}
private void setCrontabMangeEntity(CrontabMangeEntity crontabMangeEntity) {
this.crontabMangeEntity = crontabMangeEntity;
}
public OriginalDataService getOriginalDataService() {
return originalDataService;
}
private void setOriginalDataService(OriginalDataService originalDataService) {
this.originalDataService = originalDataService;
}
public DutiesAgency(CrontabMangeEntity crontabMangeEntity,OriginalDataService originalDataService){
this.crontabMangeEntity=crontabMangeEntity;
this.originalDataService=originalDataService;
}
}


在action里调用任务的添加任务,定时内容由前台配置,服务在action里注入,将定时内容和服务包装在代理里。

quartzUntils.addJob(new DutiesAgency(crontabMangeEntity,originalDataService));


以上代码简单实现了动态可配置的定时任务。

本次动态的定时任务,为能够使用originalDataService,经过几番资料查询,请教大神,最终也只是实现了,但直觉上不是最佳的方式。以下几种方式均无法实现originalDataService服务;在execute中使用:至于为什么Spring注解失效,分别做了如下测试。

1)在每次MyJob类中execute方法调用时,其构造函数是执行的;

2)将一个Action类(项目采用了Spring+struts2框架)类实现Job接口,在action的execute定时执行时,该action的注解成员也均为null;

3)项目在加载时,originalDataService、MyJob以及originalDataService类的构造函数是执行的;

4在MyJob.execute的方法里直接实例化服务类,而在服务类中不使用注解/配置方式,能够实现,但和整个项目编码方式迥异,不爽。

部分代码如下:

@Resource(name="OriginalDataService")
private OriginalDataService originalDataService;//尝试1)采用注解,execute里调用为null

OriginalDataService originalDataService=new OriginalDataService();//尝试2)错

OriginalDataService originalDataService=new OriginalDataServiceImpl();//尝试3,可以实例化OriginalDataServiceImpl,但OriginalDataServiceImpl类中的注解成员为null,不行。
时间匆忙,有时间再研究学习关于定时任务,充实本帖,待续...

此外,真诚感谢以下博客提供宝贵的实现代码:

1、Spring定时任务的几种实现

2、Spring定时任务之quartz

3、Quartz2.x增删改查工具类


4、Quartz在Spring中如何动态配置时间

5、Spring3整合Quartz2实现定时任务二:动态添加任务
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: