您的位置:首页 > 编程语言 > Java开发

spring+quartz 动态任务方案

2015-08-19 15:42 561 查看
公司目前有这样的需求,结合spring+quartz开发个后台的WEB管理系统,系统主要包括以下功能: 

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

   后台系统的应用领域: 

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

  以前没搞过这方面应用,比较头疼,经过google、百度,初步方案实现如下: 
  
  1、实现个servlet用于启动quartz调度。 
   
  
  程序如下: 
 

Java代码  


  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管理并执行。 
    
   

Java代码  


@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的接口: 
  

Java代码  


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);  

}  

   实现类: 
 

Java代码  


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”名实现任务的动态分配 

Java代码  


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的配置文件: 
 

Java代码  


<?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久未果,还请大家帮忙分析,或者对后台管理系统有更好的需求方案。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: