Spring4+Quartz2集群下动态创建编辑Job

quartz实现原理与集群原理自行百度,本文提供quartz2.2.1版本集群环境动态创建、调度、暂停、恢复、删除Job方法。

1.quartz集群依赖数据库脚本

quartz集群依赖数据库脚本

2.quartz简单监控表


quartz监控表

3.监控列表与新建页面示例


监控列表


Job新建页面

4.quartz.properties示例

org.quartz.scheduler.instanceName = THScheduler 

org.quartz.scheduler.instanceId = AUTO 

 org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool 

org.quartz.threadPool.threadCount = 10 

org.quartz.threadPool.threadPriority = 5 

org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

org.quartz.jobStore.misfireThreshold = 60000 

org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate 

org.quartz.jobStore.tablePrefix = QRTZ_ 

org.quartz.jobStore.maxMisfiresToHandleAtATime=10 

org.quartz.jobStore.isClustered = true 

 org.quartz.jobStore.clusterCheckinInterval = 20000

5.容器中基本配置 Spring-quartz.xml示例

<bean name="THScheduler " lazy-init="true" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> 

         <property name="dataSource"> <ref bean="dataSource" /> </property>

         <property name="applicationContextSchedulerContextKey" value="applicationContext" />

         <property name="configLocation" value="classpath:quartz.properties" /> 

         <!-- overwriteExistingJobs:覆盖任务调度器中同名的jobDetail,避免只修改了CronExpression所造成的不能重新生效情况 --> 

         <property name="overwriteExistingJobs" value="true" /> 

</bean>

6.quartz管理类示例

/**

* 修改任务Cron

*/

public void modifyTigger(String name, String group, String cron)throws SchedulerException {

        Scheduler scheduler = SPRING_CONTEXT.getBean(Scheduler.class);

        TriggerKey key = TriggerKey.triggerKey(name, group);

        Trigger.TriggerState triggerState = scheduler.getTriggerState(key);

        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(key).withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();

        scheduler.rescheduleJob(key, trigger);

        JobKey k =new JobKey(name, group);

        log.info("修改任务:{}", name);

        if(!JobDetails.NORMAL.equals(triggerState.name())){

                scheduler.pauseJob(k);

        }

}

/**

* 添加Job

* @param jobName job名称

* @param cls    job执行类

* @param group  群组名称

* @param cron    cron表达式

*/

public void addJob(String jobName, Class cls, String group, String cron)throws SchedulerException {

        Scheduler sched = SPRING_CONTEXT.getBean(Scheduler.class);

        // 用于描叙Job实现类及其他的一些静态信息,构建一个作业实例

        JobDetail jobDetail = JobBuilder.newJob(cls).withIdentity(jobName, group).build();

        // 构建一个触发器,规定触发的规则

        Trigger trigger = TriggerBuilder.newTrigger()// 创建一个新的TriggerBuilder来规范一个触发器

            .withIdentity(jobName, group)// 给触发器起一个名字和组名

            .startNow()// 立即执行

            .withSchedule(CronScheduleBuilder.cronSchedule(cron))// 触发器的执行时间

            .build();// 产生触发器

        // 调度Job

        sched.scheduleJob(jobDetail, trigger);

        log.debug("添加任务:{},{},{}", jobName, cls, cron);

        if (!sched.isShutdown()) {

                sched.start();

        }

}

/**

* 暂停一个任务

*/

public void pauseJob(String jobName, String jobGroupName)throws Exception {

        JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);

        Scheduler sched = SPRING_CONTEXT.getBean(Scheduler.class);

        sched.pauseJob(jobKey);

        log.info("暂停任务:{}", jobName);

}

/**

* 恢复一个任务

*/

public void resumeJob(String jobName, String jobGroupName)throws Exception {

        JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);

        Scheduler sched = SPRING_CONTEXT.getBean(Scheduler.class);

        sched.resumeJob(jobKey);

        log.info("恢复任务:{}", jobName);

}

/**

* 移除一个任务

*/

public void removeJob(String jobName, String group)throws SchedulerException {

        Scheduler sched = SPRING_CONTEXT.getBean(Scheduler.class);

        JobKey jobKey =new JobKey(jobName, group);

        // 停止触发器

        sched.pauseJob(jobKey);

        sched.unscheduleJob(new TriggerKey(jobName, group));// 移除触发器

        sched.deleteJob(jobKey);// 删除任务

        log.info("移除任务:{}", jobName);

}

/**

* 启动所有定时任务

*/

public void startJobs() {

        try {

                Scheduler sched = SPRING_CONTEXT.getBean(Scheduler.class);

                sched.start();

        }catch (Exception e) {

                throw new RuntimeException(e);

        }

}

7.web层示例(QuartzService中的方法均为对job监控表进行的单表crud操作)

/**

* Job列表

*/

@RequestMapping(path ="/quartz/list")

public Page findList(HttpServletRequest req){

        log.info("查询job列表");

        return SPRING_CONTEXT.getBean(QuartzService.class).findList(getPageSort(req));

}

/**

* 跳转至job新建页面

*/

@RequestMapping(path ="/quartz/to/add/{id}")

public ModelAndView toAdd(@PathVariable Long id, HttpServletRequest req){

        log.info("调整至新建页面,jobId为{}", id);

        ModelAndView m =new ModelAndView();

        if(id != -1){

                m.addObject("job", SPRING_CONTEXT.getBean(QuartzService.class).findById(id));

        }

        m.addObject("id", id);

        m.setViewName("/dth/quartz/edit.jsp");

        return m;

}

/**

* 编辑Job

*/

@RequestMapping(path ="/quartz/save")

public String save(JobDetails jobDetails, HttpServletRequest req)throws Exception {

    return -1 == jobDetails.getId() ? addJob(jobDetails, getSessionUser(req)) : updateJob(jobDetails);

}

/**

* 新建

*/

public String addJob(JobDetails jobDetails, User user)throws BusinessException {

        log.info("新建job,jobId为{}", jobDetails.getId());

        SPRING_CONTEXT.getBean(QuartzService.class).addJob(jobDetails, user);

        return success("ok");

}

/**

* 修改Cron与备注

*/

public String updateJob(JobDetails jobDetails)throws Exception {

        log.info("修改Cron与备注,jobId为{}", jobDetails.getId());

        SPRING_CONTEXT.getBean(QuartzService.class).updateJob(jobDetails);

        SPRING_CONTEXT.getBean(QuartzManagerService.class).modifyTigger(jobDetails.getNames(), jobDetails.getGroups(),         jobDetails.getCron());

        return success("ok");

}

/**

* 开始调度Job

*/

@RequestMapping(path ="/quartz/schedu/{id}")

public String scheduJob(@PathVariable Long id)throws Exception {

        log.info("开始调度Job,jobId为{}", id);

        JobDetails j = SPRING_CONTEXT.getBean(QuartzService.class).findById(id);

        j.setStatus(JobDetails.NORMAL);

        SPRING_CONTEXT.getBean(QuartzService.class).updateJobStatus(j);

        SPRING_CONTEXT.getBean(QuartzManagerService.class).addJob(j.getNames(), Class.forName(j.getClassName()), j.getGroups(),         j.getCron());

        return success("ok");

}

/**

* 恢复执行Job

*/

@RequestMapping(path ="/quartz/start/{id}")

public String startJob(@PathVariable Long id)throws Exception {

        log.info("恢复执行Job,jobId为{}", id);

        JobDetails j = SPRING_CONTEXT.getBean(QuartzService.class).findById(id);

        j.setStatus(JobDetails.NORMAL);

        SPRING_CONTEXT.getBean(QuartzService.class).updateJobStatus(j);

        SPRING_CONTEXT.getBean(QuartzManagerService.class).resumeJob(j.getNames(), j.getGroups());

        return success("ok");

}

/**

* 暂停Job

*/

@RequestMapping(path ="/quartz/stop/{id}")

public String stopJob(@PathVariable Long id)throws Exception {

        log.info("暂停Job,jobId为{}", id);

        JobDetails j = SPRING_CONTEXT.getBean(QuartzService.class).findById(id);

        j.setStatus(JobDetails.PAUSED);

        SPRING_CONTEXT.getBean(QuartzService.class).updateJobStatus(j);

        SPRING_CONTEXT.getBean(QuartzManagerService.class).pauseJob(j.getNames(), j.getGroups());

        return success("ok");

}

/**

* 删除Job

*/

@RequestMapping(path ="/quartz/delete/{id}")

public String deleteJob(@PathVariable Long id)throws Exception {

        log.info("删除Job,jobId为{}", id);

        JobDetails j = SPRING_CONTEXT.getBean(QuartzService.class).findById(id);

        SPRING_CONTEXT.getBean(QuartzManagerService.class).removeJob(j.getNames(), j.getGroups());

        SPRING_CONTEXT.getBean(QuartzService.class).deleteJob(j); 

        return success("ok");

}

8.实时获取内存中job信息

@RequestMapping(path ="/testQuartz/list")

public List list()throws SchedulerException {

        List list =new ArrayList<>();

        Scheduler scheduler = SPRING_CONTEXT.getBean(Scheduler.class);

        for (String groupName : scheduler.getJobGroupNames()) {

                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(groupName))) {

                           JobDetails j =new JobDetails();

                            j.setNames(jobKey.getName());

                            j.setGroups(jobKey.getGroup());

                            j.setStatus(scheduler.getTriggerState(TriggerKey.triggerKey(jobKey.getName(), jobKey.getGroup())).toString());

                            TriggerKey triggerKey =new TriggerKey(jobKey.getName(), jobKey.getGroup());

                            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

                            j.setCron(trigger.getCronExpression());

                            j.setPreDate(trigger.getPreviousFireTime());

                            j.setNextDate(trigger.getNextFireTime());

                            JobDetail jobDetail = scheduler.getJobDetail(new JobKey(jobKey.getName(), jobKey.getGroup()));

                            Class objJobClass = jobDetail.getJobClass();

                            j.setClassName(objJobClass.getName());

                            j.setMethodName(objJobClass.getMethods()[0].getName());

                            list.add(j);

                    }

        }

        return list;

}

9.多个节点时间必须同步

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269