公司目前有这样的需求,结合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);
- }
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管理并执行。
- @Service
- public class StartJobService implements Runnable {
- /**
- * log4j 记录器
- */
- private static final Logger log = Logger.getLogger(StartJobService.class);
- @Resource
- private 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);
- }
- }
- }
@Service
public class StartJobService implements Runnable {
/**
* log4j 记录器
*/
private static final Logger log = Logger.getLogger(StartJobService.class);
@Resource
private 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 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());
- // 实例化SimpleTrigger
- SimpleTrigger 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 stub
- return 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);
- }
- }
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());
// 实例化SimpleTrigger
SimpleTrigger 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 stub
return 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;