公司目前有这样的需求,结合spring+quartz开发个后台的WEB管理系统,系统主要包括以下功能:
1、动态添加、修改和删除数据源,并加入到spring管理。
2、动态注册、修改和删除任务(需要实现的具体quartz业务类),并加入到quartz管理。
3、提供上传第三方包的功能。(主要考虑实现的业务类,需要引入其他的jar包)。
4、在线日志查询分析。
。。。
后台系统的应用领域:
1、执行多个数据库之间的数据交换服务。
2、架设系统与银行之间的通讯服务。
。。。
以前没搞过这方面应用,比较头疼,经过google、百度,初步方案实现如下:
1、实现个servlet用于启动quartz调度。
程序如下:
2、到xml文件查询前台添加的任务队列,加入quartz管理并执行。
3、封装SchedulerService实现quartz调度的方法
封装的出来quartz的接口:
实现类:
4、覆盖QuartzJobBean的executeInternal方法,根据“name”名实现任务的动态分配
5、quartz的配置文件:
以上是实现的主要代码: 目前可以实现任务的动态添加并执行,现在的问题是添加多个任务时,最后面的任务会覆盖之前所有的任务。
检查了N久未果,还请大家帮忙分析,或者对后台管理系统有更好的需求方案。
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管理并执行。
- @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 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;
- Object[] obj = null;
- par = new Class[2];
- par[0] = String.class;
- par[1] = String.class;
- obj = new Object[2];
- obj[0] = name;
- obj[1] = desc;
- Constructor ct = cls.getConstructor(par);
- service = ct.newInstance(obj);
- Method meth = cls.getMethod("start");
- meth.invoke(service);
- cls = null;
- } catch (Exception e) {
- log.error("运行注册服务【" + name + "】出现异常", e);
- }
- }
- }
- }
5、quartz的配置文件:
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
- "http://www.springframework.org/dtd/spring-beans.dtd">
- <beans>
- <bean id="schedulerFactory" singleton="false"
- class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
- <property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
- <property name="configLocation" value="classpath:quartz.properties" />
- </bean>
- <bean id="jobDetail" singleton="false"
- class="org.springframework.scheduling.quartz.JobDetailBean">
- <property name="jobClass">
- <value>
- com.xeranx.summer.scheduling.EnhanceQuartzJobBean
- </value>
- </property>
- </bean>
- <bean id="schedulerService" singleton="false"
- class="com.xeranx.summer.scheduling.service.SchedulerServiceImpl">
- <property name="jobDetail">
- <ref bean="jobDetail" />
- </property>
- <property name="scheduler">
- <ref bean="schedulerFactory" />
- </property>
- </bean>
- </beans>
以上是实现的主要代码: 目前可以实现任务的动态添加并执行,现在的问题是添加多个任务时,最后面的任务会覆盖之前所有的任务。
检查了N久未果,还请大家帮忙分析,或者对后台管理系统有更好的需求方案。