Spring4+Quartz2集群动态创建任务

     公司最近需要使用Quartz集群来实现任务的动态创建和删除,之前自己只是用过配置好的单机版的,而且是定时

执行的任务,正好借这个机会深入学习一下Quartz。

     在正式开始之前,我们先来了解下,spring3.1以下的版本必须使用quartz1.x系列,3.1以上的版本才支持quartz 2.x,不然会出错。至于原因,则是spring对于quartz的支持实现,org.springframework.scheduling.quartz.CronTriggerBean继承了org.quartz.CronTrigger,在quartz1.x系列中org.quartz.CronTrigger是个类,而在quartz2.x系列中org.quartz.CronTrigger变成了接口,从而造成无法用spring的方式配置quartz的触发器(trigger)。公司现运行项目用的spring版本是4.2.2.RELEASE,所有我选取的quartz版本是2.2.1。

     最终实现的功能:

     1)项目启动时,可动态添加、删除、修改和执行定时任务;

     2)因为是集群,一个实例运行挂了,保存在数据库的定时任务可以继续执行;而且定时任务只能被其中一个实例执行。


    一、引入Maven坐标


		
		
			org.quartz-scheduler
			quartz
			2.2.1
		
		
			org.quartz-scheduler
			quartz-jobs
			2.2.1
		


     二、创建数据库表


     在Quartz包下docs/dbTables,选择对应的数据库脚本,创建相应的数据库表即可,我用的是mysql5.6,这里有一个需要注意的地方,mysql5.5之前用的表存储引擎是MyISAM,使用的是表级锁,锁发生冲突的概率比较高,并发度低;5.6之后默认的存储引擎为InnoDB,InnoDB采用的锁机制是行级锁,并发度也较高。而quartz集群使用数据库锁的

机制来来实现同一个任务在同一个时刻只被实例执行,所以为了防止冲突,我们建表的时候要选取InnoDB作为表的存

储引擎。如下:


      Spring4+Quartz2集群动态创建任务_第1张图片


     三、配置quartz.xml






	
	
		
			
		
		
		
		
			
				CRMscheduler
				AUTO
				
				org.quartz.simpl.SimpleThreadPool
				20
				5
				120000
				
				org.quartz.impl.jdbcjobstore.JobStoreTX
				
				true
				15000
				1
				
				qrtz_
				qzDS
			
		

		
		
		
		
		

	


     引入spring配置文件:


     配置文件中SchedulerFactoryBean中的dataSource用指定spring中之前配置好的就可以。


     四、实现Job接口


     我们在动态添加任务的时候需要用到这个类。


public class AllPushNotifyJob implements Job {
    private static final Log logger = LogFactory.getLog(AllPushNotifyJob.class);

    private AllPushMessageService allPushMessageService;

    public AllPushNotifyJob() {
        allPushMessageService = (AllPushMessageService) SpringContext.getBeanByName("allPushMessageService");
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDataMap dataMap = jobExecutionContext.getJobDetail().getJobDataMap();

        AllPushMessage  allPushMessage = (AllPushMessage) dataMap.get("allPushMessage");

        Date expectTriggerTime = allPushMessage.getPush_time();

        Date realTriggerTime = new Date();
        logger.info("execute category notify job with expect trigger time:" + DateUtils.format(expectTriggerTime, "yyyy-MM-dd HH:mm:ss Z"));
        logger.info("real notify time:" + DateUtils.format(realTriggerTime, "yyyy-MM-dd HH:mm:ss Z"));
        allPushMessageService.enforceAllPush(allPushMessage);
    }
}


     五、JobScheduler管理任务


@Service
public class AllPushJobScheduler {
    private static final Log logger = LogFactory.getLog(AllPushJobScheduler.class);

    public void start() {
        logger.info("start category update notify scheduler");
        schedulerFactoryBean.start();

    }

    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;

    /**
     * 添加任务
     * @param allPushMessage
     */
	public void scheduleNotifyJob(AllPushMessage allPushMessage) {
		if (allPushMessage.getPush_time().compareTo(new Date()) < 0) {
			allPushMessage.setPush_time(DateUtils.addSeconds(new Date(), 10));
		}

		Scheduler scheduler = schedulerFactoryBean.getScheduler();
		JobKey jobKey = getJobKey(allPushMessage);
		try {
			if (scheduler.checkExists(jobKey)) {
				logger.info("all push job existed!:" + jobKey.getName());
				return;
			}
		} catch (SchedulerException e) {
			logger.error("get exception:" + e.getMessage(), e);
		}

		logger.info("schedule all push job at:"+allPushMessage.getPush_time() +" with job name pushID" + jobKey.getName());
		JobDataMap jobData = new JobDataMap();
		jobData.put("allPushMessage", allPushMessage);

		JobDetail notifyJob = JobBuilder.newJob(AllPushNotifyJob.class)
				.setJobData(jobData).withIdentity(jobKey).build();
		SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
		trigger.setName("trigger-" + jobKey.getName());
		trigger.setJobDetail(notifyJob);
		trigger.setStartTime(allPushMessage.getPush_time());
		trigger.setRepeatCount(0);
		trigger.afterPropertiesSet();

		try {
			schedulerFactoryBean.getScheduler().scheduleJob(notifyJob,
					trigger.getObject());
		} catch (SchedulerException e) {
			logger.error("get exception when executing quartz job" + e);
		}

	}


    /**
     * 删除任务
     * @param allPushMessage
     * @throws Exception
     */
    public void deleteJob(AllPushMessage allPushMessage)throws Exception{

        try{
            //删除定时任务时   先暂停任务,然后再删除
            JobKey jobKey = getJobKey(allPushMessage);
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            scheduler.pauseJob(jobKey);
            scheduler.deleteJob(jobKey);
        }catch(Exception e){
            System.out.println("删除定时任务失败"+e);
            throw new Exception("删除定时任务失败");
        }
    }


    /**
     * 获取jobKey
     * @param allPushMessage
     * @return
     */
    public JobKey getJobKey(AllPushMessage allPushMessage) {

        return JobKey.jobKey(String.valueOf(allPushMessage.getPush_id()));
    }

    /**
     * 更新定时任务
     * @param
     * @param
     * @throws Exception
     */
    public void updateJob(AllPushMessage allPushMessage)throws Exception{
        try {
            TriggerKey triggerKey =getTriggerKey(String.valueOf(allPushMessage.getPush_id()));
            Scheduler scheduler = schedulerFactoryBean.getScheduler();

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

            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).build();

            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            System.out.println("更新定时任务失败"+e);
            throw new Exception("更新定时任务失败");
        }
    }

    /**
     * 获取触发器key
     *
     * @param
     * @param
     * @return
     */
    public static TriggerKey getTriggerKey(String jobkey) {

        return TriggerKey.triggerKey(jobkey);
    }



    /**
     * 暂停定时任务
     * @param allPushMessage
     * @throws Exception
     */
    public void pauseJob(AllPushMessage allPushMessage) throws Exception {

        JobKey jobKey = JobKey.jobKey(String.valueOf(allPushMessage.getPush_id()));
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            scheduler.pauseJob(jobKey);
        } catch (SchedulerException e) {
            System.out.println("暂停定时任务失败"+e);
            throw new Exception("暂停定时任务失败");
        }
    }

    /**
     * 恢复任务
     * @param
     * @param
     * @param
     * @throws Exception
     */
    public void resumeJob(AllPushMessage allPushMessage) throws Exception {

        JobKey jobKey = JobKey.jobKey(String.valueOf(allPushMessage.getPush_id()));
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            scheduler.resumeJob(jobKey);
        } catch (SchedulerException e) {
            System.out.println("恢复定时任务失败"+e);
            throw new Exception("恢复定时任务失败");
        }
    }

    /**
     * 运行一次任务
     * @param allPushMessage
     * @throws Exception
     */
    public void runOnce(AllPushMessage allPushMessage) throws Exception {
        JobKey jobKey = JobKey.jobKey(String.valueOf(allPushMessage.getPush_id()));
        try {
            Scheduler scheduler = schedulerFactoryBean.getScheduler();
            scheduler.triggerJob(jobKey);
        } catch (SchedulerException e) {
            System.out.println("运行任务失败"+e);
            throw new Exception("运行一次定时任务失败");
        }
    }

}


     最后,在需要你的代码中调用添加、删除、修改任务的方法就可以了,喵




你可能感兴趣的:(Quartz)