Java的任务调度

一、浅谈Job&JobDetail

    JobDetail为Job实例提供了许多设置属性,以及JobDataMap成员属性变量,它用来存储特定的Job实例的状态信息,调度器需要借助JobDetail对象来添加Job实例

1.1    重要属性

  •     name
  •     jobClass
  •     group
  •     jobDataMap
package com.demo;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

import java.text.SimpleDateFormat;
import java.util.Date;

public class HelloScheduler {
    public static void main(String[] args) throws SchedulerException {
//        创建一个jobdetail实例
        JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("myJob", "1").build();
        System.out.println("jobDetail's name : "+jobDetail.getKey().getName());
        System.out.println("jobDetail's group : "+jobDetail.getKey().getGroup());
        System.out.println("jobDetail's jobClass : "+jobDetail.getJobClass().getName());
        
//         创建一个trigger实例,定义该job立即执行,并且每隔2秒钟执行一次,直到永远
        Trigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "1").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever()).build();
//         创建Scheduler实例
        SchedulerFactory sfact = new StdSchedulerFactory();
        Scheduler scheduler = sfact.getScheduler();
        scheduler.start(); //执行
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time is"+ sf.format(date)+"HelloScheduler");
        scheduler.scheduleJob(jobDetail,trigger); //绑定
    }
}
package com.demo;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.text.SimpleDateFormat;
import java.util.Date;

public class HelloJob implements Job {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//        打印当前的执行时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time is"+ sf.format(date));
        System.out.println();
//        编写具体的业务逻辑
        System.out.println("Hello World!");
    }
}

1.2     JobExecutionContext

        当Scheduler调用一个Job,就会将JobExecutionContext传递给Job的execute()方法;

        Job不能通过JoExecutionContext对象访问到Quartz运行时候的环境以及Job本身的明细数据

二、    JobDataMap

2.1    JobDataMap是什么

  • 在进行任务调度时JobDataMap存储在JobExecutionContext中,非常方便获取
  • JobDataMap可以用来装在任何可序列化的数据对象,job实例对象被执行时,这些参数对象会传递给它
  • JobDataMap实现了JDK的Map接口,并且添加了一些非常方便的方法来存取基本数据类型

2.2    获取JobDataMap的两种方式

  • 从Map中直接获取
  • Job实现类中添加setter方法对应JobDataMap的键值(Quartz框架默认的JobFactory实现类在初始化job实例对象时会自动的调用这些setter方法
package com.demo;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.TriggerKey;

import java.text.SimpleDateFormat;
import java.util.Date;

public class HelloJob implements Job {


    private  String message;
    private  Float FloatJobValue;
    private  Double  DoubleTriggerValue;


    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//        打印当前的执行时间
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time is" + sf.format(date));
        System.out.println();
//        获取jobKey信息
        JobKey key = jobExecutionContext.getJobDetail().getKey();
        System.out.println("My Job name and group are " + key.getName() + ":" + key.getGroup());
//        获取triggerKey信息
        TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
        System.out.println("My Trigger name and group are " + triggerKey.getName() + ":" + triggerKey.getGroup());
//        获取自己输入的信息
        //mergedDataMap 包含dataMap与tdataMap,如果两者有相同的key,trigger的key的信息会覆盖带你job的信息
//        JobDataMap mergedDataMap = jobExecutionContext.getMergedJobDataMap();
        //job的map信息
//        JobDataMap dataMap = jobExecutionContext.getJobDetail().getJobDataMap();
        //trigger的map信息
//        JobDataMap tdataMap = jobExecutionContext.getTrigger().getJobDataMap();
//        String jobMsg = mergedDataMap.getString("message");
//        float jobFloatValue = mergedDataMap.getFloat("FloatJobValue");
//        String triggerMsg = mergedDataMap.getString("message");
//        double doubleTriggerValue = mergedDataMap.getDouble("DoubleTriggerValue");
        System.out.println("jobMsg is " + message);
        System.out.println("jobFloatValue is " + FloatJobValue);
//        System.out.println("triggerMsg is " + triggerMsg);
        System.out.println("doubleTriggerValue is " + DoubleTriggerValue);

    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Float getFloatJobValue() {
        return FloatJobValue;
    }

    public void setFloatJobValue(Float floatJobValue) {
        FloatJobValue = floatJobValue;
    }

    public Double getDoubleTriggerValue() {
        return DoubleTriggerValue;
    }

    public void setDoubleTriggerValue(Double doubleTriggerValue) {
        DoubleTriggerValue = doubleTriggerValue;
    }

}
 
package com.demo;

import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;

import java.text.SimpleDateFormat;
import java.util.Date;

public class HelloScheduler {
    public static void main(String[] args) throws SchedulerException {
//        创建一个jobdetail实例
        JobDetail jobDetail = JobBuilder
                .newJob(HelloJob.class)
                .withIdentity("myJob", "1")
                .usingJobData("message", "hello myJob1")  //存储在JobdateMap中
                .usingJobData("FloatJobValue", 3.14F)
                .build();

//         创建一个trigger实例,定义该job立即执行,并且每隔2秒钟执行一次,直到永远
        Trigger trigger = TriggerBuilder
                .newTrigger()
                .withIdentity("myTrigger", "1")
                .usingJobData("message", "hello myTrigger1")
                .usingJobData("DoubleTriggerValue", 2.0D)
                .startNow()
                .withSchedule(
                        SimpleScheduleBuilder
                                .simpleSchedule()
                                .withIntervalInSeconds(2)
                                .repeatForever()
                )
                .build();
//         创建Scheduler实例
        SchedulerFactory sfact = new StdSchedulerFactory();
        Scheduler scheduler = sfact.getScheduler();
        scheduler.start(); //执行
        Date date = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("Current Time is" + sf.format(date) + "HelloScheduler");
        scheduler.scheduleJob(jobDetail, trigger); //绑定
    }
}

三、    浅谈Tigger

3.1    Quartz框架中的Trigger,用到比较多的是CronTriggerImpl、SimpleTriggerImpl

3.2    触发器通用属性:

 

  • JobKey -- 表示job实例的标识,触发器触发时,该指定的job实例会执行
  • StartTime -- 表示触发器的时间表首次被触发时间,它的值的类型是Java.util.Date
  • EndTime -- 指定触发器的不再被触发的时间,它的值的类型是Java.util.Date

3.3    SimpleTrigger的作用

        在一个指定时间段内执行一次作业任务,或是在指定的时间间隔内多次执行作业任务

        3.3.1    SimpleTrigger需要注意的点

                重复次数可以为0,正整数或者是SimpleTrigger.REPEAT_INDEFINITELY(无穷)常量值

                重复执行间隔必须为0或者长整数

                一旦指定了endTime参数,那么它会覆盖重复次数参数的效果

3.4    CronTrigger 

        3.4.1    CronTrigger的作用:基于日历的作业调度器,而不是像SimpleTrigger那样精确指定间隔时间,比SimpleTrigger更常用

        3.4.2    Cron表达式

                    用于配置CronTrigger实例

                    是由7个字表达式组成的字符串,描述了时间表的详细信息

                    格式:[秒] [分] [时] [日] [月] [周] [年] 

                Java的任务调度_第1张图片     

每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:

  (1)*:表示匹配该域的任意值。假如在Minutes域使用*, 即表示每分钟都会触发事件。

  (2)?:只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。因为DayofMonth和DayofWeek会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管星期几都会触发,实际上并不是这样。

  (3)-:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次 

  (4)/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次. 

  (5),:表示列出枚举值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。 

  (6)L:表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。 

  (7)W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。

  (8)LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。 

  (9)#:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三

     3.4.23    常用表达式 

 

      (1)0 0 2 1 * ? *   表示在每月的1日的凌晨2点调整任务

  (2)0 15 10 ? * MON-FRI   表示周一到周五每天上午10:15执行作业

  (3)0 15 10 ? 6L 2002-2006   表示2002-2006年的每个月的最后一个星期五上午10:15执行作

  (4)0 0 10,14,16 * * ?   每天上午10点,下午2点,4点 

  (5)0 0/30 9-17 * * ?   朝九晚五工作时间内每半小时 

  (6)0 0 12 ? * WED    表示每个星期三中午12点 

  (7)0 0 12 * * ?   每天中午12点触发 

  (8)0 15 10 ? * *    每天上午10:15触发 

  (9)0 15 10 * * ?     每天上午10:15触发 

  (10)0 15 10 * * ? *    每天上午10:15触发 

  (11)0 15 10 * * ? 2005    2005年的每天上午10:15触发 

  (12)0 * 14 * * ?     在每天下午2点到下午2:59期间的每1分钟触发 

  (13)0 0/5 14 * * ?    在每天下午2点到下午2:55期间的每5分钟触发 

  (14)0 0/5 14,18 * * ?     在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 

  (15)0 0-5 14 * * ?    在每天下午2点到下午2:05期间的每1分钟触发 

  (16)0 10,44 14 ? 3 WED    每年三月的星期三的下午2:10和2:44触发 

  (17)0 15 10 ? * MON-FRI    周一至周五的上午10:15触发 

  (18)0 15 10 15 * ?    每月15日上午10:15触发 

  (19)0 15 10 L * ?    每月最后一日的上午10:15触发 

  (20)0 15 10 ? * 6L    每月的最后一个星期五上午10:15触发 

  (21)0 15 10 ? * 6L 2002-2005   2002年至2005年的每月的最后一个星期五上午10:15触发 

  (22)0 15 10 ? * 6#3   每月的第三个星期五上午10:15触发

四、    浅谈Scheduler

    4.1    回顾Quartz的三个核心概念

 

  • 调度器
  • 任务
  • 触发器

    4.2    Scheduler创建方式  -- StdSchedulerFactory

 

  •       使用一组参数(java.util.properties)来创建和初始化Quartz调度器
  •        配置参数 一般存储在quartz.properties中
  •        调用getScheduler方法就能创建和初始化调度起对象

     4.3        scheduler的主要方法

 

  •    Date scheduleJob(JobDetail var1, Trigger var2) 
  •    void start()  -- 重启
  •    void standby()  -- 挂起
  •    void shutdown()  -- 关闭,不可被重启

     4.4      quart.properties -- 加载顺序,先去src目录查找,如果没有会去quartz的jar包中查找quartz.properties文件

        4.4.1    组成部分

 

  •      调度器属性
  •      线程池属性
  •      作业存储设置
  •      插件配置 

        4.4.2    线程池属性

 

  •   threadCount 
  •  threadPriority   1-10,正常默认5
  •  org.quartz.threadPool.class  

    五、给大家提供一个方便的Quartz工具类

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import org.quartz.CalendarIntervalScheduleBuilder;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.Trigger.TriggerState;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;


public class QuartzManager {

	private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();

	/**
	 * @Description: 添加一个定时任务
	 * @param jobName
	 *            任务名
	 * @param jobGroupName
	 *            任务组名,传null使用默认任务组名
	 * @param jobClass
	 *            任务
	 * @param triggerName
	 *            触发器名
	 * @param triggerGroupName
	 *            触发器组名,传null使用默认触发器名
	 * @param time
	 *            时间
	 * @param isClear
	 *            是否是清除任务
	 * @param dataMap
	 *            jobClass需要的参数
	 */
	public static void addJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
			Class jobClass, String time, boolean isClear, Map dataMap) {
		try {
			// 获取调度任务工厂
			Scheduler scheduler = schedulerFactory.getScheduler();
			// 创建一个JobDetail
			JobDataMap jobDataMap = new JobDataMap(dataMap);
			JobDetail job = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).usingJobData(jobDataMap)
					.build();
			// 创建一个CronTrigger
			Trigger trigger = null;
			TriggerBuilder builder = TriggerBuilder.newTrigger();
			builder.withIdentity(triggerName, triggerGroupName);
			if (!isClear) {
				builder.startNow();
				builder.withSchedule(SimpleScheduleBuilder.repeatMinutelyForever(Integer.parseInt(time)));				
			} else {
				String startTime = DateUtils.parseDate(new Date(), "yyyyMMdd") + " "
						+ dataMap.get("autoClearStartTime");
				builder.startAt(new SimpleDateFormat("yyyyMMdd HH:mm:ss").parse(startTime));
				builder.withSchedule(CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
						.withIntervalInDays(Integer.parseInt(time)));
			}
			trigger = builder.build();
			// 将JobDetail和CronTrigger加入调度任务
			scheduler.scheduleJob(job, trigger);
			if (!scheduler.isShutdown()) {
				scheduler.start();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @Description: 修改一个任务
	 * 
	 * @param jobName
	 *            任务名
	 * @param jobGroupName
	 *            任务组名
	 * @param triggerName
	 *            触发器名
	 * @param triggerGroupName
	 *            触发器组名
	 * @param cron
	 *            定时表达式
	 * @param dataMap
	 *            jobClass需要的参数
	 */
	public static void modifyJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName,
			Class jobClass, String minute, boolean isCron, Map dataMap) {
		try {
			// 删除原有的定时任务
			removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
			// 添加新的定时任务
			addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, minute, isCron, dataMap);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @Description: 移除一个任务
	 * 
	 * @param jobName
	 *            任务名
	 * @param jobGroupName
	 *            任务组名
	 * @param triggerName
	 *            触发器名
	 * @param triggerGroupName
	 *            触发器组名
	 */
	public static void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
		try {
			Scheduler scheduler = schedulerFactory.getScheduler();
			// 找到对应的触发器
			TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
			// 停止触发器
			scheduler.pauseTrigger(triggerKey);
			// 移除触发器
			scheduler.unscheduleJob(triggerKey);
			// 删除任务
			scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @Description:启动所有定时任务
	 */
	public static void startJobs() {
		try {
			Scheduler scheduler = schedulerFactory.getScheduler();
			scheduler.start();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * @Description:关闭所有定时任务
	 */
	public static void shutdownJobs() {
		try {
			Scheduler scheduler = schedulerFactory.getScheduler();
			if (!scheduler.isShutdown()) {
				scheduler.shutdown();
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
	
	/**
	 * @Description:检查Job运行状态
	 */
	public static boolean checkJobsRunStatus(String triggerName, String triggerGroupName) {
		try {
			Scheduler scheduler = schedulerFactory.getScheduler();
			// 找到对应的触发器
			TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
			TriggerState triggerState = scheduler.getTriggerState(triggerKey);
			String state = triggerState.name();
			if(TriggerState.NORMAL.name().equals(state) || TriggerState.BLOCKED.name().equals(state) || TriggerState.COMPLETE.name().equals(state)){
				return true;
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return false;
	}
}

 

你可能感兴趣的:(Java的任务调度)