项目中要用到定时任务,所以自己研究了一下,下面就我们项目中用到的spring-quartz的实现步骤做以下分享。
一:用到的技术(maven构建的spring-mvc项目)
Spring-mvc
Mybatis,
Maven
Quartz
二:配置
1):首先在pom.xml中引入quartz的jar包(项目中的其他的jar包这里就不再概述)
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
2):在spring的配置文件applicationg.xml(不同的项目的名称可能不一样)的头部添加如下声明(红色部分为quartz需要添加的声明)。
<?xml version="1.0"encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:aop="http://www.springframework.org/schema/aop"xmlns:task="http://www.springframework.org/schema/task"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.1.xsd">
再次在该配置文件中将quartz纳入到spring管理中
<!-- 定时器配置开始 -->
<bean id="simpleJobFactory"class="org.quartz.simpl.SimpleJobFactory" />
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobFactory" ref="simpleJobFactory" />
</bean>
<!-- 定时器配置结束 -->
3):我们的spring的quartz配置就完成了
二:代码实现
1):要将定时任务纳入到管理中,我们首先要将定时任务持久化到数据库中(持久化表的脚本就不概述了)下面为持久化类。
public class ScheduleJob{
private Long id;//唯一标示
private String jobId;//定时任务唯一(uuid)
private String jobName;//定时任务名称
private String jobGroup; //定时任务所属组
private String jobStatus; //定时任务状态(0:开启,1:禁用,2:删除)
private String cronExpression; //定时任务表达式
private String cronClass; //定时任务执行类
private String descs; //定时任务描述
//setting,getting方法省略
}
2):定时任务业务处理层(用的是注解的方式)
@Component
public class QuartzJobService {
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
//开启
public void startJob(ScheduleJob job) throws Exception{
stopJob(job);
// log.info("start Job (start) >jobid:"+job.getId());
Scheduler scheduler = schedulerFactoryBean.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobId(),job.getJobGroup());
//获取trigger,即在spring配置文件中定义的 bean id="myTrigger"
CronTrigger trigger = (CronTrigger)scheduler.getTrigger(triggerKey);
//不存在,创建一个
if (null == trigger) {
Job jb = (Job)Class.forName(job.getCronClass()).newInstance();
JobDetail jobDetail = JobBuilder.newJob(jb.getClass())
.withIdentity(job.getJobId(), job.getJobGroup()).build();
jobDetail.getJobDataMap().put(job.getJobId(), job);
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job
.getCronExpression());
//按新的cronExpression表达式构建一个新的trigger
trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobId(),job.getJobGroup()).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
} else {
// Trigger已存在,那么更新相应的定时设置
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job
.getCronExpression());
//按新的cronExpression表达式重新构建trigger
trigger =trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder).build();
//按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
}
// log.info("start Job (end) >jobid:"+job.getId());
}
//停止
public booleanstopJob(ScheduleJob job) {
// log.info("stop Job (start) >jobid:"+job.getId());
String jobId =job.getJobId();
String jobGroupId = job.getJobGroup();
if (jobId.equals("") || jobGroupId.equals("")) {
return false;
}
Scheduler scheduler = schedulerFactoryBean.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobId(),job.getJobGroup());
try {
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (null != trigger) {
scheduler.deleteJob(trigger.getJobKey());
}
} catch (SchedulerException e) {
// log.error(e.getMessage(), e);
e.printStackTrace();
return false;
}
// log.info("stop Job (end) >jobid:"+job.getId());
return true;
}
}
这里面的方法我就不再一一做讲解了(这里参考的是网上的分享(原文找不到了…))。
3):下面就是具体的控制层的了。
@Controller
@RequestMapping("/job")
public class JobController extends BaseController {
@Autowired
private QuartzJobService quartzJobService;
@Autowired
private ScheduleJobService scheduleJobService;
// private final Logger log = Logger.getLogger(JobController.class);
/**
* 开启定时任务
* @param id
* @return
* @author zhangzq-a
*/
@RequestMapping(value="/start", produces = "text/plain;charset=UTF-8")
@ResponseBody
public String startTask(Long[] id){
if(id==null||id.length<1){
return "redirect:/job/list";
}
for(Long jId :id){
ScheduleJob job = scheduleJobService.get(jId);
if(job!=null){
// log.info("开启定时任务start》定时任务ID:"+jId);
if("1".equals(job.getJobStatus())){
ScheduleJob j = new ScheduleJob();
j.setId(job.getId());
j.setJobStatus("0");
scheduleJobService.update(j);
}
try {
quartzJobService.startJob(job);
// log.info("开启定时任务end》定时任务ID:"+jId);
return "true";
} catch (Exception e) {
// log.error(e.getMessage(), e);
}
}
}
return "定时任务启动失败,请联系管理员";
}
/**
* 禁用任务
* @param id
* @return
* @author zhangzq-a
*/
@RequestMapping(value="/stop", produces = "text/plain;charset=UTF-8")
@ResponseBody
public String stopTask(Long[] id){
if(id==null||id.length<1){
return "redirect:/job/list";
}
for(Long jId :id){
ScheduleJob job = scheduleJobService.get(jId);
if(job!=null){
// log.info("禁用定时任务start》定时任务ID:"+jId);
if("0".equals(job.getJobStatus())){
ScheduleJob j = new ScheduleJob();
j.setId(job.getId());
j.setJobStatus("1");
scheduleJobService.update(j);
}
try {
quartzJobService.stopJob(job);
// log.info("禁用定时任务end》定时任务ID:"+jId);
return "true";
} catch (Exception e) {
// log.error(e.getMessage(), e);
}
}
}
return "定时任务启动失败,请联系管理员";
}
/**
* 删除定时任务
* @param id
* @return
* @author zhangzq-a
*/
@RequestMapping("/delete")
@ResponseBody
public String deleteTask(Long[] id){
if(id==null||id.length<1){
return "redirect:/job/list";
}
for(Long jId :id){
ScheduleJob job = scheduleJobService.get(jId);
if(job!=null){
// log.info("删除定时任务start》定时任务ID:"+jId);
// if("1".equals(job.getJobStatus())){
ScheduleJob j = new ScheduleJob();
j.setId(job.getId());
j.setJobStatus("2");
scheduleJobService.update(j);
// }
try {
quartzJobService.stopJob(job);
// log.info("删除定时任务end》定时任务ID:"+jId);
return "true";
} catch (Exception e) {
// log.error(e.getMessage(), e);
}
}
}
return "定时任务删除失败,请联系管理员";
}
/**
* 获取定时任务
* @param id
* @return
* @author zhangzq-a
*/
@RequestMapping(value="/get")
@ResponseBody
public ScheduleJob getTask(Long id){
if(id==null){
return new ScheduleJob();
}
return scheduleJobService.get(id);
}
/**
* 新增或修改定时任务
* @param id
* @return
* @author zhangzq-a
*/
@RequestMapping(value="/edit", produces = "text/plain;charset=UTF-8")
@ResponseBody
public String editTask(ScheduleJob job){
if(job.getId()!=null){//修改
ScheduleJob job2 = scheduleJobService.get(job.getId());
if(job2==null){
return "定时任务不存在";
}else if("2".equals((job2.getJobStatus()))){
return "定时任务已被删除";
}else {
boolean boo = scheduleJobService.checkUnion(job);
if(!boo){
return "定时任务已经存在";
}
boo = quartzJobService.stopJob(job2);
if(!boo){
return "定时任务禁用失败";
}
// log.info("修改定时任务start》定时任务ID:"+job.getId());
scheduleJobService.update(job);
if("0".equals((job.getJobStatus()))){
String msg = startTask(new Long[]{job.getId()});
if(!"true".equalsIgnoreCase(msg)){
return "定时开启失败";
}
}
// log.info("修改定时任务end》定时任务ID:"+job.getId());
}
}else{//保存
boolean boo = scheduleJobService.checkUnion(job);
if(!boo){
return "定时任务已经存在";
}
// log.info("新增定时任务start》定时任务ID:"+job.getId());
scheduleJobService.insert(job);
if("0".equalsIgnoreCase(job.getJobStatus())){
String msg = startTask(new Long[]{job.getId()});
if(!"true".equalsIgnoreCase(msg)){
return "定时开启失败";
}
}
// log.info("修改定时任务end》定时任务ID:"+job.getId());
}
return "true";
}
}
4):下面就是具体的前端的控制实现了,这里 我也就不做相应的分享了...
上面的定时任务只能够满足部分要求,对于负载和容错都不满足,对于分布式是不能满足要求的,分布式的实现方式目前正在研究中…