前端时间开发接触了一个开源框架jeecg,里面封装了spring与quartz整合的定时任务实现方式。因为之前尝试过单纯使用quartz来实现定时任务,遇到一些问题,比如,无法通过spring注入的方式添加自己的注入类。
首先了解一下,定时任务有三种技术实现方式:java自带的Timer类,可以让程序保持一定频度执行,但是无法按照某个时间执行;quartz,一个功能强大的调度器,是由java编写的作业调度框架,简单易用;spring3.0之后自带task,轻量级Quartz。
梳理实现过程:
(1)pom文件引入需要jar包:这里spring版本为4.0.9.RELEASE,quartz版本为1.6.2
(2)xml文件配置执行策略,执行的触发器,并将触发器注入到任务调度器中
//要执行的发送邮件的方法
//每分钟执行一次
由上面配置可知,定时任务是由spring注入的方式,因此要执行的方法直接按照spring的标准就可以 了。这样定时任务就算完成了,系统启动后,会按照执行策略动态执行。
(3)实现定时任务管理过程:
(3.1)定义定时间任务实体(描述任务信息):
@Entity
@Table(name = "t_s_timetask", schema = "")
@DynamicUpdate(true)
@DynamicInsert(true)
@SuppressWarnings("serial")
public class TSTimeTaskEntity implements java.io.Serializable {
/**id*/
private java.lang.String id;
/**任务ID*/
private java.lang.String taskId;
/**任务描述*/
private java.lang.String taskDescribe;
/**cron表达式*/
private java.lang.String cronExpression;
/**是否生效了0未生效,1生效了*/
private java.lang.String isEffect;
/**是否运行0停止,1运行*/
private java.lang.String isStart;
/**创建时间*/
private java.util.Date createDate;
/**创建人ID*/
private java.lang.String createBy;
/**创建人名称*/
private java.lang.String createName;
/**修改时间*/
private java.util.Date updateDate;
/**修改人ID*/
private java.lang.String updateBy;
/**修改人名称*/
private java.lang.String updateName;
/**执行的job名称*/
private java.lang.String jobeName;
{get;set}
}
任务id要与xml任务调度器配置一致。
(3.3)controller端实现:
@Controller
@RequestMapping("/timeTaskController")
public class TimeTaskController extends BaseController {
@Autowired
private TimeTaskServiceI timeTaskService;
@Autowired
private DynamicTask dynamicTask;
@Autowired
private SystemService systemService;
/**
* 定时任务管理列表 页面跳转
*
* @return
*/
@RequestMapping(params = "timeTask")
public ModelAndView timeTask(HttpServletRequest request) {
return new ModelAndView("system/timetask/timeTaskList");
}
/**
* easyui AJAX请求数据
*
* @param request
* @param response
* @param dataGrid
* @param user
*/
@RequestMapping(params = "datagrid")
public void datagrid(TSTimeTaskEntity timeTask,HttpServletRequest request, HttpServletResponse response, DataGrid dataGrid) {
CriteriaQuery cq = new CriteriaQuery(TSTimeTaskEntity.class, dataGrid);
//查询条件组装器
org.jeecgframework.core.extend.hqlsearch.HqlGenerateUtil.installHql(cq, timeTask, request.getParameterMap());
this.timeTaskService.getDataGridReturn(cq, true);
TagUtil.datagrid(response, dataGrid);
}
/**
* 删除定时任务管理
*
* @return
*/
@RequestMapping(params = "del")
@ResponseBody
public AjaxJson del(TSTimeTaskEntity timeTask, HttpServletRequest request) {
String message = null;
AjaxJson j = new AjaxJson();
timeTask = systemService.getEntity(TSTimeTaskEntity.class, timeTask.getId());
message = "定时任务管理删除成功";
timeTaskService.delete(timeTask);
systemService.addLog(message, Globals.Log_Type_DEL, Globals.Log_Leavel_INFO);
j.setMsg(message);
return j;
}
/**
* 添加定时任务管理
*
* @param ids
* @return
*/
@RequestMapping(params = "save")
@ResponseBody
public AjaxJson save(TSTimeTaskEntity timeTask, HttpServletRequest request) {
String message = null;
AjaxJson j = new AjaxJson();
CronTrigger trigger = new CronTrigger();
try {
trigger.setCronExpression(timeTask.getCronExpression());
} catch (ParseException e) {
j.setMsg("Cron表达式错误");
return j;
}
if (StringUtil.isNotEmpty(timeTask.getId())) {
message = "定时任务管理更新成功";
TSTimeTaskEntity t = timeTaskService.get(TSTimeTaskEntity.class, timeTask.getId());
try {
if(!timeTask.getCronExpression().equals(t.getCronExpression())){
timeTask.setIsEffect("0");
}
MyBeanUtils.copyBeanNotNull2Bean(timeTask, t);
timeTaskService.saveOrUpdate(t);
systemService.addLog(message, Globals.Log_Type_UPDATE, Globals.Log_Leavel_INFO);
} catch (Exception e) {
e.printStackTrace();
message = "定时任务管理更新失败";
}
} else {
message = "定时任务管理添加成功";
timeTaskService.save(timeTask);
systemService.addLog(message, Globals.Log_Type_INSERT, Globals.Log_Leavel_INFO);
}
j.setMsg(message);
return j;
}
/**
* 定时任务管理列表页面跳转
*
* @return
*/
@RequestMapping(params = "addorupdate")
public ModelAndView addorupdate(TSTimeTaskEntity timeTask, HttpServletRequest req) {
if (StringUtil.isNotEmpty(timeTask.getId())) {
timeTask = timeTaskService.getEntity(TSTimeTaskEntity.class, timeTask.getId());
req.setAttribute("timeTaskPage", timeTask);
}
return new ModelAndView("system/timetask/timeTask");
}
/**
* 更新任务时间使之生效
*/
@RequestMapping(params = "updateTime")
@ResponseBody
public AjaxJson updateTime(TSTimeTaskEntity timeTask, HttpServletRequest request) {
AjaxJson j = new AjaxJson();
timeTask = timeTaskService.get(TSTimeTaskEntity.class, timeTask.getId());
boolean isUpdate = dynamicTask.updateCronExpression(timeTask.getTaskId() , timeTask.getCronExpression());
if(isUpdate){
timeTask.setIsEffect("1");
timeTask.setIsStart("1");
timeTaskService.updateEntitie(timeTask);
}
j.setMsg(isUpdate?"定时任务管理更新成功":"定时任务管理更新失败");
return j;
}
/**
* 启动或者停止任务
*/
@RequestMapping(params = "startOrStopTask")
@ResponseBody
public AjaxJson startOrStopTask(TSTimeTaskEntity timeTask, HttpServletRequest request) {
AjaxJson j = new AjaxJson();
boolean isStart = timeTask.getIsStart().equals("1");
timeTask = timeTaskService.get(TSTimeTaskEntity.class, timeTask.getId());
boolean isSuccess = false;
try {
isSuccess = dynamicTask.startOrStop(timeTask.getTaskId() ,isStart);
} catch (Exception e) {
j.setMsg(isSuccess?"定时任务管理更新成功":"定时任务管理更新失败");
}
if(isSuccess){
timeTask.setIsStart(isStart?"1":"0");
timeTaskService.updateEntitie(timeTask);
systemService.addLog((isStart?"开启任务":"停止任务")+timeTask.getTaskId(),
Globals.Log_Type_UPDATE, Globals.Log_Leavel_INFO);
}
j.setMsg(isSuccess?"定时任务管理更新成功":"定时任务管理更新失败");
return j;
}
}
动态调整定时任务:
/**
* 动态任务,用以动态调整Spring的任务
* @author JueYue
* @date 2013-9-20
* @version 1.0
*/
@Service(value="dynamicTask")
public class DynamicTask {
private static Logger logger = Logger.getLogger(DynamicTask.class);
@Resource
private Scheduler schedulerFactory;
/**
* 更新定时任务的触发表达式
*
* @param triggerName
* 触发器名字
* @param start
* 触发表达式
* @return 成功则返回true,否则返回false
*/
public boolean startOrStop(String triggerName,
boolean start) {
try {
CronTrigger trigger = (CronTrigger) getTrigger(triggerName,
Scheduler.DEFAULT_GROUP);
if(start){
schedulerFactory.resumeTrigger(trigger.getName(), trigger.getGroup());
logger.info("trigger the start successfully!!");
}else{
schedulerFactory.pauseTrigger(trigger.getName(), trigger.getGroup());
logger.info("trigger the pause successfully!!");
}
return true;
} catch (SchedulerException e) {
logger.error("Fail to reschedule. " + e);
return false;
}
}
/**
* 更新定时任务的触发表达式
*
* @param triggerName
* 触发器名字
* @param cronExpression
* 触发表达式
* @return 成功则返回true,否则返回false
*/
public boolean updateCronExpression(String triggerName,
String cronExpression) {
try {
CronTrigger trigger = (CronTrigger) getTrigger(triggerName,
Scheduler.DEFAULT_GROUP);
if (trigger == null) {
return false;
}
if (StringUtils.equals(trigger.getCronExpression(), cronExpression)) {
logger.info("cronExpression is same with the running Schedule , no need to update.");
return true;
}
trigger.setCronExpression(cronExpression);
schedulerFactory.rescheduleJob(trigger.getName(), trigger.getGroup(),
trigger);
updateSpringMvcTaskXML(trigger,cronExpression);
logger.info("Update the cronExpression successfully!!");
return true;
} catch (ParseException e) {
logger.error("The new cronExpression - " + cronExpression
+ " not conform to the standard. " + e);
return false;
} catch (SchedulerException e) {
logger.error("Fail to reschedule. " + e);
return false;
}
}
/**
* 获取触发器
*
* @param triggerName
* 触发器名字
* @param groupName
* 触发器组名字
* @return 对应Trigger
*/
private Trigger getTrigger(String triggerName, String groupName) {
Trigger trigger = null;
if (StringUtils.isBlank(groupName)) {
logger.warn("Schedule Job Group is empty!");
return null;
}
if (StringUtils.isBlank(triggerName)) {
logger.warn("Schedule trigger Name is empty!");
return null;
}
try {
trigger = schedulerFactory.getTrigger(triggerName, groupName);
} catch (SchedulerException e) {
logger.warn("Fail to get the trigger (triggerName: " + triggerName
+ ", groupName : " + groupName + ")");
return null;
}
if (trigger == null) {
logger.warn("Can not found the trigger of triggerName: "
+ triggerName + ", groupName : " + groupName);
}
return trigger;
}
/**
* 更新spring-mvc-timeTask.xml 配置文件
* @param trigger
* @param cronExpression
*/
@SuppressWarnings("unchecked")
public synchronized static void updateSpringMvcTaskXML(CronTrigger trigger, String cronExpression) {
Document document = null;
File file = null;
SAXReader saxReader = new SAXReader();
try {
URI url = DynamicTask.class.getClassLoader().getResource("spring-mvc-timeTask.xml").toURI();
file = new File(url.getPath());
document = saxReader.read(new FileInputStream(file));
} catch (Exception e) {
logger.error("读取系统中用到的SQL 语句XML出错");
throw new RuntimeException("---------读取spring-mvc-timeTask.xml文件出错:" + e.getMessage());
}
Element root = document.getRootElement();
List beans = root.elements();
for (Element bean : beans) {
if(bean.attribute("id")!=null&&
bean.attribute("id").getValue().equals(trigger.getName())){
beans = bean.elements();
for (Element temp : beans) {
if(temp.attribute("name")!=null&&
temp.attribute("name").getValue().equals("cronExpression")){
temp.attribute("value").setValue(cronExpression);
break;
}
}
break;
}
}
XMLWriter fileWriter = null;
try {
OutputFormat xmlFormat = OutputFormat.createPrettyPrint();
xmlFormat.setEncoding("utf-8");
fileWriter = new XMLWriter(new FileOutputStream(file),xmlFormat);
fileWriter.write(document);
} catch (IOException e) {
e.printStackTrace();
}finally{
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
出现内存溢出时解决方案:http://blog.csdn.net/dslztx/article/details/47276953
学习参考资料:《Spring 整合 Quartz 实现动态定时任务》
文章demo:http://download.csdn.net/detail/u012466304/9906761