spring實現可動態修改時間定時任務
阿新 • • 發佈:2019-02-05
前端時間開發接觸了一個開源框架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檔案配置執行策略,執行的觸發器,並將觸發器注入到任務排程器中
<!-- 定時任務配置 scheduler 方式 --> <context:component-scan base-package="org.jeecgframework.core.timer" /> <task:executor id="executor" pool-size="5" /> <task:scheduler id="scheduler" pool-size="10" /> <task:annotation-driven executor="executor" scheduler="scheduler" /> <!-- 定時任務配置 smsSendTask 可配置到管理介面 --> <bean id="smsSendTaskJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="smsSendTask" /> //要執行的傳送郵件的方法 <property name="targetMethod" value="run" /> <property name="concurrent" value="true" /> </bean> <bean id="smsSendTaskCronTrigger" class="org.jeecgframework.core.timer.DataBaseCronTriggerBean"> <property name="jobDetail" ref="smsSendTaskJob" /> <property name="cronExpression" value="0 0/1 * * * ?" /> //每分鐘執行一次 </bean> <!-- 定時任務排程器 org.jeecgframework.core.timer.DataBaseSchedulerFactoryBean--> <bean id="schedulerFactory" lazy-init="false" autowire="no" class="org.jeecgframework.web.system.util.SchedulerFactoryBeanWithShutdownDelay"> <property name="triggers"> <list> <ref bean="smsSendTaskCronTrigger" /> </list> </property> </bean>
由上面配置可知,定時任務是由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} }
(3.2)前臺實現效果:
任務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<Element> 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();
}
}
}
}
在產品中,定時任務主要應用於統計資料,每日,每季度統計資料報表!是否建立會員使用者到期情況等。