spring+quartz 动态任务议案
spring+quartz 动态任务方案公司目前有这样的需求,结合spring+quartz开发个后台的WEB管理系统,系统主要包
spring+quartz 动态任务方案
公司目前有这样的需求,结合spring+quartz开发个后台的WEB管理系统,系统主要包括以下功能:
? 1、动态添加、修改和删除数据源,并加入到spring管理。
? 2、动态注册、修改和删除任务(需要实现的具体quartz业务类),并加入到quartz管理。
? 3、提供上传第三方包的功能。(主要考虑实现的业务类,需要引入其他的jar包)。
? 4、在线日志查询分析。
? 。。。
?? 后台系统的应用领域:
? 1、执行多个数据库之间的数据交换服务。
? 2、架设系统与银行之间的通讯服务。
? 。。。
? 以前没搞过这方面应用,比较头疼,经过google、百度,初步方案实现如下:
?
? 1、实现个servlet用于启动quartz调度。
??
?
? 程序如下:
?
public class DispatchJobServlet extends HttpServlet {private static final long serialVersionUID = -3920177706344758439L;private ApplicationContext ctx;public DispatchJobServlet() {super();// 初始化自定义类加载器,主要用于加载第三方包和服务程序。ServiceStartup manguage = new ServiceStartup();manguage.startUp();}/** * 初始化 */public void init(ServletConfig config) throws ServletException {super.init(config);ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());StartJobService taskStartService = (StartJobService) ctx.getBean("startJobService");//启用个线程开始任务调度ExecutorService exec = Executors.newCachedThreadPool();exec.execute(taskStartService);}}
?? 2、到xml文件查询前台添加的任务队列,加入quartz管理并执行。
???
???
@Servicepublic class StartJobService implements Runnable {/** * log4j 记录器 */private static final Logger log = Logger.getLogger(StartJobService.class);@Resourceprivate SchedulerService schedulerService;public void run() {try {while (true) {List<JobBo> list = DomParser.findAllJobXml("db.service.xml");Iterator<JobBo> i = list.iterator();while (i.hasNext()) {JobBo job = i.next();// 如果任务队列不存在则注册并运行if (!ServiceManager.queryExistsJob(job.getName())) {try {schedulerService.schedule(job);ServiceManager.getJobHolder().put(job.getName(),job);} catch (Exception e) {log.error("服务【" + job.getName() + "】启动失败!", e);throw new SummerException("服务【" + job.getName()+ "】启动失败!");}}Thread.sleep(3000);}}} catch (SummerException e) {throw e;} catch (Exception e) {log.error("调度任务出现异常!", e);}}}
?? 3、封装SchedulerService实现quartz调度的方法
?? 封装的出来quartz的接口:
??
public interface SchedulerService {/** * 自定义任务对象并启动任务 * * @param job * 任务队列业务对象 */void schedule(JobBo job);/** * 取得所有调度Triggers * * @return */List<Map<String, Object>> getQrtzTriggers();/** * 根据名称和组别暂停Tigger * * @param triggerName * @param group */void pauseTrigger(String triggerName, String group);/** * 恢复Trigger * * @param triggerName * @param group */void resumeTrigger(String triggerName, String group);/** * 删除Trigger * * @param triggerName * @param group */boolean removeTrigdger(String triggerName, String group);}
?? 实现类:
?
public class SchedulerServiceImpl implements SchedulerService {private static final Logger log = LoggerFactory.getLogger(SchedulerServiceImpl.class);private Scheduler scheduler;private JobDetail jobDetail;public void setScheduler(Scheduler scheduler) {this.scheduler = scheduler;}public void setJobDetail(JobDetail jobDetail) {this.jobDetail = jobDetail;}/** * 自定义任务对象并启动任务 */public void schedule(JobBo job) {// trigger分类String category = job.getCategory();try {if ("cron".equals(category)) {scheduleCron(job);} else {scheduleSimple(job);}} catch (Exception e) {log.error("任务调度过程中出现异常!");throw new SummerException(e);}}/** * simple任务触发 * * @param job */private void scheduleSimple(JobBo job) {String name = getTriggerName(job.getName());// 实例化SimpleTriggerSimpleTrigger simpleTrigger = new SimpleTrigger();// 这些值的设置也可以从外面传入,这里采用默放值simpleTrigger.setJobName(jobDetail.getName());simpleTrigger.setJobGroup(Scheduler.DEFAULT_GROUP);simpleTrigger.setRepeatInterval(1000L);// 设置名称simpleTrigger.setName(name);// 设置Trigger分组String group = job.getGroup();if (StringUtils.isEmpty(group)) {group = Scheduler.DEFAULT_GROUP;}simpleTrigger.setGroup(group);// 设置开始时间Timestamp startTime = job.getStartTime();if (null != startTime) {simpleTrigger.setStartTime(new Date());}// 设置结束时间Timestamp endTime = job.getEndTime();if (null != endTime) {simpleTrigger.setEndTime(endTime);}// 设置执行次数int repeatCount = job.getRepeatCount();if (repeatCount > 0) {simpleTrigger.setRepeatCount(repeatCount);}// 设置执行时间间隔long repeatInterval = job.getRepeatInterval();if (repeatInterval > 0) {simpleTrigger.setRepeatInterval(repeatInterval * 1000);}try {JobDataMap jobData = new JobDataMap();jobData.put("name", job.getName());jobData.put("desc", job.getDesc());jobDetail.setJobDataMap(jobData);scheduler.addJob(jobDetail, true);scheduler.scheduleJob(simpleTrigger);scheduler.rescheduleJob(simpleTrigger.getName(), simpleTrigger.getGroup(), simpleTrigger);} catch (SchedulerException e) {log.error("任务调度出现异常!");log.error(LogGenerator.getInstance().generate(e));throw new SummerException("任务调度出现异常!");}}/** * cron任务触发 * * @param job */private void scheduleCron(JobBo job) {String name = getTriggerName(job.getName());try {JobDataMap jobData = new JobDataMap();jobData.put("name", job.getName());jobData.put("desc", job.getDesc());jobDetail.setJobDataMap(jobData);scheduler.addJob(jobDetail, true);CronTrigger cronTrigger = new CronTrigger(name, job.getGroup(),jobDetail.getName(), Scheduler.DEFAULT_GROUP);cronTrigger.setCronExpression(job.getCronExpression());scheduler.scheduleJob(cronTrigger);scheduler.rescheduleJob(cronTrigger.getName(), cronTrigger.getGroup(), cronTrigger);} catch (Exception e) {log.error("执行cron触发器出现异常!", e);throw new SummerException("执行cron触发器出现异常!");}}public void schedule(String name, Date startTime, Date endTime,int repeatCount, long repeatInterval, String group) {if (name == null || name.trim().equals("")) {name = UUID.randomUUID().toString();} else {// 在名称后添加UUID,保证名称的唯一性name += "&" + UUID.randomUUID().toString();}try {scheduler.addJob(jobDetail, true);SimpleTrigger SimpleTrigger = new SimpleTrigger(name, group,jobDetail.getName(), Scheduler.DEFAULT_GROUP, startTime,endTime, repeatCount, repeatInterval);scheduler.scheduleJob(SimpleTrigger);scheduler.rescheduleJob(SimpleTrigger.getName(), SimpleTrigger.getGroup(), SimpleTrigger);} catch (SchedulerException e) {throw new RuntimeException(e);}}public void pauseTrigger(String triggerName, String group) {try {scheduler.pauseTrigger(triggerName, group);// 停止触发器} catch (SchedulerException e) {throw new SummerException(e);}}public void resumeTrigger(String triggerName, String group) {try {scheduler.resumeTrigger(triggerName, group);// 重启触发器} catch (SchedulerException e) {log.error("重启触发器失败!");throw new SummerException(e);}}public boolean removeTrigdger(String triggerName, String group) {try {scheduler.pauseTrigger(triggerName, group);// 停止触发器return scheduler.unscheduleJob(triggerName, group);// 移除触发器} catch (SchedulerException e) {throw new SummerException(e);}}private Timestamp parseDate(String time) {try {return Timestamp.valueOf(time);} catch (Exception e) {log.error("日期格式错误{},正确格式为:yyyy-MM-dd HH:mm:ss", time);throw new SummerException(e);}}public List<Map<String, Object>> getQrtzTriggers() {// TODO Auto-generated method stubreturn null;}/** * 获取trigger名称 * * @param name * @return */private String getTriggerName(String name) {if (StringUtils.isBlank(StringUtils.trim(name))) {name = UUID.randomUUID().toString();} else {name = name.substring(name.lastIndexOf(".") + 1);// 在名称后添加UUID,保证名称的唯一性name += "&" + UUID.randomUUID().toString();}return StringUtils.trim(name);}}
? 4、覆盖QuartzJobBean的executeInternal方法,根据“name”名实现任务的动态分配
public?class?EnhanceQuartzJobBean?extends?QuartzJobBean?{ ??????/** ??????*?log4j?记录器 ??????*/??????private?static?final?Logger?log?=?Logger ??????????????.getLogger(EnhanceQuartzJobBean.class); ????????@Override??????protected?void?executeInternal(JobExecutionContext?context) ??????????????throws?JobExecutionException?{ ??????????try?{ ??????????????JobDetail?t?=?context.getJobDetail(); ??????????????JobDataMap?map?=?t.getJobDataMap(); ??????????????String?name?=?map.getString("name"); ??????????????String?desc?=?map.getString("desc"); ??????????????ServiceStartupManguage?manguage?=?new?ServiceStartupManguage(); ??????????????manguage.runService(name,?desc); ??????????}?catch?(Exception?e)?{ ??????????????log.error("执行任务出现异常",?e); ??????????} ??????} ?????? ??????public?class?ServiceStartup?{ ??????/** ??????*?log4j?记录器 ??????*/??????private?static?final?Logger?log?=?Logger ??????????????.getLogger(ServiceStartupManguage.class); ????????public?void?startUp()?{ ??????????//?启动动态重新加载类的服务 ??????????StringBuilder?sb?=?new?StringBuilder(1024); ??????????sb.append(ServiceManager.getHome()?+?"work"); ??????????String?jarPath?=?ServiceManager.getHome()?+?"ext"; ??????????//?遍历ext文件夹,寻找jar文件 ??????????File?dir?=?new?File(jarPath); ??????????String[]?subFiles?=?dir.list(); ??????????for?(int?i?=?0;?i?<?subFiles.length;?i++)?{ ??????????????File?file?=?new?File(jarPath?+?System.getProperty("file.separator") ??????????????????????+?subFiles[i]); ??????????????if?(file.isFile()?&&?subFiles[i].endsWith("jar"))?{ ??????????????????sb.append(File.pathSeparator?+?jarPath ??????????????????????????+?System.getProperty("file.separator")?+?subFiles[i]); ??????????????} ??????????} ??????????ServiceManager.checker?=?new?ClassModifyChecker(ServiceManager.getHome()); ??????????ServiceManager.loader?=?new?ServiceClassLoad(DispatchJobServlet.class??????????????????.getClassLoader(),?(String)?sb.toString(),?ServiceManager.checker); ??????????ServiceManager.classPath?=?sb.toString(); ??????} ????????/** ??????*?启动后台服务 ??????*? ??????*?@author?任鹤峰?2009-02-03 ??????*?@param?name ??????*?@param?desc ??????*?@throws?ClassNotFoundException ??????*?@throws?NoSuchMethodException ??????*?@throws?InstantiationException ??????*?@throws?IllegalAccessException ??????*?@throws?InvocationTargetException ??????*/??????@SuppressWarnings("unchecked") ??????public?void?runService(String?name,?String?desc) ??????????????throws?ClassNotFoundException,?NoSuchMethodException, ??????????????InstantiationException,?IllegalAccessException, ??????????????InvocationTargetException?{ ??????????try?{ ??????????????Object?service; ??????????????Class?cls?=?null; ??????????????if?(null?!=?ServiceManager.loader)?{ ??????????????????cls?=?ServiceManager.getLoader().loadClass(name); ??????????????}?else?{ ??????????????????cls?=?Class.forName(name); ??????????????} ??????????????Class[]?par?=?null; ??