spring+quartz 动态任务方案

来源:互联网 发布:qq克隆软件 编辑:程序博客网 时间:2024/06/04 18:59
公司目前有这样的需求,结合spring+quartz开发个后台的WEB管理系统,系统主要包括以下功能: 

  1、动态添加、修改和删除数据源,并加入到spring管理。 
  2、动态注册、修改和删除任务(需要实现的具体quartz业务类),并加入到quartz管理。 
  3、提供上传第三方包的功能。(主要考虑实现的业务类,需要引入其他的jar包)。 
  4、在线日志查询分析。 
  。。。 

   后台系统的应用领域: 

  1、执行多个数据库之间的数据交换服务。 
  2、架设系统与银行之间的通讯服务。 
  。。。 

  以前没搞过这方面应用,比较头疼,经过google、百度,初步方案实现如下: 
  
  1、实现个servlet用于启动quartz调度。 
   
  
  程序如下: 
 
Java代码  收藏代码
  1.   public class DispatchJobServlet extends HttpServlet {  
  2.   
  3. private static final long serialVersionUID = -3920177706344758439L;  
  4. private ApplicationContext ctx;  
  5.   
  6. public DispatchJobServlet() {  
  7.     super();  
  8.     //  初始化自定义类加载器,主要用于加载第三方包和服务程序。  
  9.     ServiceStartup manguage = new ServiceStartup();  
  10.     manguage.startUp();  
  11. }  
  12.   
  13. /** 
  14.  * 初始化 
  15.  */  
  16. public void init(ServletConfig config) throws ServletException {  
  17.     super.init(config);  
  18.     ctx = WebApplicationContextUtils  
  19.             .getRequiredWebApplicationContext(config.getServletContext());  
  20.     StartJobService taskStartService = (StartJobService) ctx.getBean("startJobService");  
  21.     //启用个线程开始任务调度  
  22.     ExecutorService exec = Executors.newCachedThreadPool();  
  23.     exec.execute(taskStartService);  
  24. }  
  25.   
  26.    


   2、到xml文件查询前台添加的任务队列,加入quartz管理并执行。 
    
   
Java代码  收藏代码
  1. @Service  
  2. public class StartJobService implements Runnable {  
  3.     /** 
  4.      * log4j 记录器 
  5.      */  
  6.     private static final Logger log = Logger.getLogger(StartJobService.class);  
  7.     @Resource  
  8.     private SchedulerService schedulerService;  
  9.   
  10.     public void run() {  
  11.         try {  
  12.             while (true) {  
  13.                 List<JobBo> list = DomParser.findAllJobXml("db.service.xml");  
  14.                 Iterator<JobBo> i = list.iterator();  
  15.                 while (i.hasNext()) {  
  16.                     JobBo job = i.next();  
  17.                     // 如果任务队列不存在则注册并运行  
  18.                     if (!ServiceManager.queryExistsJob(job.getName())) {  
  19.                         try {  
  20.                             schedulerService.schedule(job);  
  21.                             ServiceManager.getJobHolder().put(job.getName(),  
  22.                                     job);  
  23.                         } catch (Exception e) {  
  24.                             log.error("服务【" + job.getName() + "】启动失败!", e);  
  25.                             throw new SummerException("服务【" + job.getName()  
  26.                                     + "】启动失败!");  
  27.                         }  
  28.                     }  
  29.                     Thread.sleep(3000);  
  30.                 }  
  31.             }  
  32.         } catch (SummerException e) {  
  33.             throw e;  
  34.         } catch (Exception e) {  
  35.             log.error("调度任务出现异常!", e);  
  36.         }  
  37.     }  
  38. }  

   3、封装SchedulerService实现quartz调度的方法 
   封装的出来quartz的接口: 
  
Java代码  收藏代码
  1. public interface SchedulerService {  
  2.   
  3.     /** 
  4.      * 自定义任务对象并启动任务 
  5.      *  
  6.      * @param job 
  7.      *            任务队列业务对象 
  8.      */  
  9.     void schedule(JobBo job);  
  10.   
  11.     /** 
  12.      * 取得所有调度Triggers 
  13.      *  
  14.      * @return 
  15.      */  
  16.     List<Map<String, Object>> getQrtzTriggers();  
  17.   
  18.     /** 
  19.      * 根据名称和组别暂停Tigger 
  20.      *  
  21.      * @param triggerName 
  22.      * @param group 
  23.      */  
  24.     void pauseTrigger(String triggerName, String group);  
  25.   
  26.     /** 
  27.      * 恢复Trigger 
  28.      *  
  29.      * @param triggerName 
  30.      * @param group 
  31.      */  
  32.     void resumeTrigger(String triggerName, String group);  
  33.   
  34.     /** 
  35.      * 删除Trigger 
  36.      *  
  37.      * @param triggerName 
  38.      * @param group 
  39.      */  
  40.     boolean removeTrigdger(String triggerName, String group);  
  41. }  


   实现类: 
 
Java代码  收藏代码
  1. public class SchedulerServiceImpl implements SchedulerService {  
  2.   
  3.     private static final Logger log = LoggerFactory  
  4.             .getLogger(SchedulerServiceImpl.class);  
  5.   
  6.     private Scheduler scheduler;  
  7.   
  8.     private JobDetail jobDetail;  
  9.   
  10.     public void setScheduler(Scheduler scheduler) {  
  11.         this.scheduler = scheduler;  
  12.     }  
  13.   
  14.     public void setJobDetail(JobDetail jobDetail) {  
  15.         this.jobDetail = jobDetail;  
  16.     }  
  17.   
  18.     /** 
  19.      * 自定义任务对象并启动任务 
  20.      */  
  21.     public void schedule(JobBo job) {  
  22.         // trigger分类  
  23.         String category = job.getCategory();  
  24.         try {  
  25.             if ("cron".equals(category)) {  
  26.                 scheduleCron(job);  
  27.             } else {  
  28.                 scheduleSimple(job);  
  29.             }  
  30.         } catch (Exception e) {  
  31.             log.error("任务调度过程中出现异常!");  
  32.             throw new SummerException(e);  
  33.         }  
  34.     }  
  35.   
  36.     /** 
  37.      * simple任务触发 
  38.      *  
  39.      * @param job 
  40.      */  
  41.     private void scheduleSimple(JobBo job) {  
  42.         String name = getTriggerName(job.getName());  
  43.         // 实例化SimpleTrigger  
  44.         SimpleTrigger simpleTrigger = new SimpleTrigger();  
  45.   
  46.         // 这些值的设置也可以从外面传入,这里采用默放值  
  47.         simpleTrigger.setJobName(jobDetail.getName());  
  48.         simpleTrigger.setJobGroup(Scheduler.DEFAULT_GROUP);  
  49.         simpleTrigger.setRepeatInterval(1000L);  
  50.         // 设置名称  
  51.         simpleTrigger.setName(name);  
  52.   
  53.         // 设置Trigger分组  
  54.         String group = job.getGroup();  
  55.         if (StringUtils.isEmpty(group)) {  
  56.             group = Scheduler.DEFAULT_GROUP;  
  57.         }  
  58.         simpleTrigger.setGroup(group);  
  59.   
  60.         // 设置开始时间  
  61.         Timestamp startTime = job.getStartTime();  
  62.         if (null != startTime) {  
  63.             simpleTrigger.setStartTime(new Date());  
  64.         }  
  65.   
  66.         // 设置结束时间  
  67.         Timestamp endTime = job.getEndTime();  
  68.         if (null != endTime) {  
  69.             simpleTrigger.setEndTime(endTime);  
  70.         }  
  71.   
  72.         // 设置执行次数  
  73.         int repeatCount = job.getRepeatCount();  
  74.         if (repeatCount > 0) {  
  75.             simpleTrigger.setRepeatCount(repeatCount);  
  76.         }  
  77.   
  78.         // 设置执行时间间隔  
  79.         long repeatInterval = job.getRepeatInterval();  
  80.         if (repeatInterval > 0) {  
  81.             simpleTrigger.setRepeatInterval(repeatInterval * 1000);  
  82.         }  
  83.         try {  
  84.             JobDataMap jobData = new JobDataMap();  
  85.             jobData.put("name", job.getName());  
  86.             jobData.put("desc", job.getDesc());  
  87.             jobDetail.setJobDataMap(jobData);  
  88.             scheduler.addJob(jobDetail, true);  
  89.             scheduler.scheduleJob(simpleTrigger);  
  90.             scheduler.rescheduleJob(simpleTrigger.getName(), simpleTrigger  
  91.                     .getGroup(), simpleTrigger);  
  92.         } catch (SchedulerException e) {  
  93.             log.error("任务调度出现异常!");  
  94.             log.error(LogGenerator.getInstance().generate(e));  
  95.             throw new SummerException("任务调度出现异常!");  
  96.         }  
  97.     }  
  98.   
  99.     /** 
  100.      * cron任务触发 
  101.      *  
  102.      * @param job 
  103.      */  
  104.     private void scheduleCron(JobBo job) {  
  105.         String name = getTriggerName(job.getName());  
  106.         try {  
  107.             JobDataMap jobData = new JobDataMap();  
  108.             jobData.put("name", job.getName());  
  109.             jobData.put("desc", job.getDesc());  
  110.             jobDetail.setJobDataMap(jobData);  
  111.             scheduler.addJob(jobDetail, true);  
  112.             CronTrigger cronTrigger = new CronTrigger(name, job.getGroup(),  
  113.                     jobDetail.getName(), Scheduler.DEFAULT_GROUP);  
  114.             cronTrigger.setCronExpression(job.getCronExpression());  
  115.             scheduler.scheduleJob(cronTrigger);  
  116.             scheduler.rescheduleJob(cronTrigger.getName(), cronTrigger  
  117.                     .getGroup(), cronTrigger);  
  118.         } catch (Exception e) {  
  119.             log.error("执行cron触发器出现异常!", e);  
  120.             throw new SummerException("执行cron触发器出现异常!");  
  121.         }  
  122.     }  
  123.   
  124.     public void schedule(String name, Date startTime, Date endTime,  
  125.             int repeatCount, long repeatInterval, String group) {  
  126.         if (name == null || name.trim().equals("")) {  
  127.             name = UUID.randomUUID().toString();  
  128.         } else {  
  129.             // 在名称后添加UUID,保证名称的唯一性  
  130.             name += "&" + UUID.randomUUID().toString();  
  131.         }  
  132.         try {  
  133.             scheduler.addJob(jobDetail, true);  
  134.             SimpleTrigger SimpleTrigger = new SimpleTrigger(name, group,  
  135.                     jobDetail.getName(), Scheduler.DEFAULT_GROUP, startTime,  
  136.                     endTime, repeatCount, repeatInterval);  
  137.             scheduler.scheduleJob(SimpleTrigger);  
  138.             scheduler.rescheduleJob(SimpleTrigger.getName(), SimpleTrigger  
  139.                     .getGroup(), SimpleTrigger);  
  140.         } catch (SchedulerException e) {  
  141.             throw new RuntimeException(e);  
  142.         }  
  143.     }  
  144.   
  145.     public void pauseTrigger(String triggerName, String group) {  
  146.         try {  
  147.             scheduler.pauseTrigger(triggerName, group);// 停止触发器  
  148.         } catch (SchedulerException e) {  
  149.             throw new SummerException(e);  
  150.         }  
  151.     }  
  152.   
  153.     public void resumeTrigger(String triggerName, String group) {  
  154.         try {  
  155.             scheduler.resumeTrigger(triggerName, group);// 重启触发器  
  156.         } catch (SchedulerException e) {  
  157.             log.error("重启触发器失败!");  
  158.             throw new SummerException(e);  
  159.         }  
  160.     }  
  161.   
  162.     public boolean removeTrigdger(String triggerName, String group) {  
  163.         try {  
  164.             scheduler.pauseTrigger(triggerName, group);// 停止触发器  
  165.             return scheduler.unscheduleJob(triggerName, group);// 移除触发器  
  166.         } catch (SchedulerException e) {  
  167.             throw new SummerException(e);  
  168.         }  
  169.     }  
  170.   
  171.     private Timestamp parseDate(String time) {  
  172.         try {  
  173.             return Timestamp.valueOf(time);  
  174.         } catch (Exception e) {  
  175.             log.error("日期格式错误{},正确格式为:yyyy-MM-dd HH:mm:ss", time);  
  176.             throw new SummerException(e);  
  177.         }  
  178.     }  
  179.   
  180.     public List<Map<String, Object>> getQrtzTriggers() {  
  181.         // TODO Auto-generated method stub  
  182.         return null;  
  183.     }  
  184.   
  185.     /** 
  186.      * 获取trigger名称 
  187.      *  
  188.      * @param name 
  189.      * @return 
  190.      */  
  191.     private String getTriggerName(String name) {  
  192.         if (StringUtils.isBlank(StringUtils.trim(name))) {  
  193.             name = UUID.randomUUID().toString();  
  194.         } else {  
  195.             name = name.substring(name.lastIndexOf(".") + 1);  
  196.             // 在名称后添加UUID,保证名称的唯一性  
  197.             name += "&" + UUID.randomUUID().toString();  
  198.         }  
  199.         return StringUtils.trim(name);  
  200.     }  
  201. }  


  4、覆盖QuartzJobBean的executeInternal方法,根据“name”名实现任务的动态分配 
Java代码  收藏代码
  1. public class EnhanceQuartzJobBean extends QuartzJobBean {  
  2.     /** 
  3.      * log4j 记录器 
  4.      */  
  5.     private static final Logger log = Logger  
  6.             .getLogger(EnhanceQuartzJobBean.class);  
  7.   
  8.     @Override  
  9.     protected void executeInternal(JobExecutionContext context)  
  10.             throws JobExecutionException {  
  11.         try {  
  12.             JobDetail t = context.getJobDetail();  
  13.             JobDataMap map = t.getJobDataMap();  
  14.             String name = map.getString("name");  
  15.             String desc = map.getString("desc");  
  16.             ServiceStartupManguage manguage = new ServiceStartupManguage();  
  17.             manguage.runService(name, desc);  
  18.         } catch (Exception e) {  
  19.             log.error("执行任务出现异常", e);  
  20.         }  
  21.     }  
  22.       
  23.     public class ServiceStartup {  
  24.     /** 
  25.      * log4j 记录器 
  26.      */  
  27.     private static final Logger log = Logger  
  28.             .getLogger(ServiceStartupManguage.class);  
  29.   
  30.     public void startUp() {  
  31.         // 启动动态重新加载类的服务  
  32.         StringBuilder sb = new StringBuilder(1024);  
  33.         sb.append(ServiceManager.getHome() + "work");  
  34.         String jarPath = ServiceManager.getHome() + "ext";  
  35.         // 遍历ext文件夹,寻找jar文件  
  36.         File dir = new File(jarPath);  
  37.         String[] subFiles = dir.list();  
  38.         for (int i = 0; i < subFiles.length; i++) {  
  39.             File file = new File(jarPath + System.getProperty("file.separator")  
  40.                     + subFiles[i]);  
  41.             if (file.isFile() && subFiles[i].endsWith("jar")) {  
  42.                 sb.append(File.pathSeparator + jarPath  
  43.                         + System.getProperty("file.separator") + subFiles[i]);  
  44.             }  
  45.         }  
  46.         ServiceManager.checker = new ClassModifyChecker(ServiceManager.getHome());  
  47.         ServiceManager.loader = new ServiceClassLoad(DispatchJobServlet.class  
  48.                 .getClassLoader(), (String) sb.toString(), ServiceManager.checker);  
  49.         ServiceManager.classPath = sb.toString();  
  50.     }  
  51.   
  52.     /** 
  53.      * 启动后台服务 
  54.      *  
  55.      * @author 任鹤峰 2009-02-03 
  56.      * @param name 
  57.      * @param desc 
  58.      * @throws ClassNotFoundException 
  59.      * @throws NoSuchMethodException 
  60.      * @throws InstantiationException 
  61.      * @throws IllegalAccessException 
  62.      * @throws InvocationTargetException 
  63.      */  
  64.     @SuppressWarnings("unchecked")  
  65.     public void runService(String name, String desc)  
  66.             throws ClassNotFoundException, NoSuchMethodException,  
  67.             InstantiationException, IllegalAccessException,  
  68.             InvocationTargetException {  
  69.         try {  
  70.             Object service;  
  71.             Class cls = null;  
  72.             if (null != ServiceManager.loader) {  
  73.                 cls = ServiceManager.getLoader().loadClass(name);  
  74.             } else {  
  75.                 cls = Class.forName(name);  
  76.             }  
  77.             Class[] par = null;  
  78.             Object[] obj = null;  
  79.             par = new Class[2];  
  80.             par[0] = String.class;  
  81.             par[1] = String.class;  
  82.             obj = new Object[2];  
  83.             obj[0] = name;  
  84.             obj[1] = desc;  
  85.             Constructor ct = cls.getConstructor(par);  
  86.             service = ct.newInstance(obj);  
  87.             Method meth = cls.getMethod("start");  
  88.             meth.invoke(service);  
  89.             cls = null;  
  90.         } catch (Exception e) {  
  91.             log.error("运行注册服务【" + name + "】出现异常", e);  
  92.         }  
  93.     }  
  94. }  
  95.       
  96. }  


  5、quartz的配置文件: 
 
Java代码  收藏代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"  
  3.  "http://www.springframework.org/dtd/spring-beans.dtd">  
  4. <beans>  
  5.     <bean id="schedulerFactory" singleton="false"  
  6.         class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
  7.         <property name="applicationContextSchedulerContextKey" value="applicationContextKey" />  
  8.         <property name="configLocation" value="classpath:quartz.properties" />  
  9.     </bean>  
  10.   
  11.     <bean id="jobDetail" singleton="false"  
  12.         class="org.springframework.scheduling.quartz.JobDetailBean">  
  13.         <property name="jobClass">  
  14.             <value>  
  15.                 com.xeranx.summer.scheduling.EnhanceQuartzJobBean  
  16.             </value>  
  17.         </property>  
  18.     </bean>  
  19.     <bean id="schedulerService" singleton="false"  
  20.         class="com.xeranx.summer.scheduling.service.SchedulerServiceImpl">  
  21.         <property name="jobDetail">  
  22.             <ref bean="jobDetail" />  
  23.         </property>  
  24.         <property name="scheduler">  
  25.             <ref bean="schedulerFactory" />  
  26.         </property>  
  27.     </bean>  
  28. </beans>  


以上是实现的主要代码: 目前可以实现任务的动态添加并执行,现在的问题是添加多个任务时,最后面的任务会覆盖之前所有的任务。 

检查了N久未果,还请大家帮忙分析,或者对后台管理系统有更好的需求方案。 
0 0
原创粉丝点击