java定时任务框架Quartz(简单调用)

  • Post author:
  • Post category:java



Quartz是一个强大任务调度框架,应用场景例如

  • 餐厅系统会在每周四晚上的22点自动审核并生成报表
  • 人事系统会在每天早晨8点给有待办的人员自动发送Email提醒


一、简单使用(重复执行)


1.引入quartz框架pom依赖

<dependency>
	<groupId>org.quartz-scheduler</groupId>
	<artifactId>quartz</artifactId>
	<version>2.3.0</version>
</dependency>


2.创建HelloJob实现Job接口

public class HelloJob implements Job{
	private static final SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		Date now = new Date();
		String currentTime = sdf.format(now);
		System.out.println("执行时间为:"+currentTime);
	}
}


3.创建HelloScheduler触发任务

public class HelloScheduler {
	public static void main(String[] args) throws SchedulerException {
		//创建jobDetail绑定HelloJob
		JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
						.withIdentity("myJob","myGroup").build();
		//创建触发器trigger每个2秒执行一次,一直执行
		Trigger trigger = TriggerBuilder.newTrigger().withIdentity("mtTrigger", "myGroup").startNow()
						.withSchedule(SimpleScheduleBuilder.simpleSchedule()
						.withIntervalInSeconds(2).repeatForever()).build();
		//创建调度者工厂
		SchedulerFactory schedulerFactory = new StdSchedulerFactory();
		//创建调度者
		Scheduler scheduler = schedulerFactory.getScheduler();
		//启动调度器
		scheduler.start();
		//设置调度任务
		scheduler.scheduleJob(jobDetail, trigger);
	}
}


执行结果:

执行时间为:2019-04-15 23:45:41
23:45:43.388 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.myJob', class=com.xuxu.quartz.HelloJob
23:45:43.388 [DefaultQuartzScheduler_Worker-9] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.myJob
23:45:43.388 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
执行时间为:2019-04-15 23:45:43
23:45:45.387 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.myJob', class=com.xuxu.quartz.HelloJob
23:45:45.387 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
23:45:45.391 [DefaultQuartzScheduler_Worker-10] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.myJob
执行时间为:2019-04-15 23:45:45

二、定时执行使用cron表达式确定时间


1同上引入pom依赖


2创建HelloJob实现job接口,任务执行时输出时间

public class HelloJob implements Job{
	private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	@Override
	public void execute(JobExecutionContext arg0) throws JobExecutionException {
		Date now = new Date();
		String currentDate = sdf.format(now);
		System.out.println("现在时间是:"+currentDate+":开始执行任务生成表格,或者发送邮件");
	}
}


3创建触发类CronScheduler

public class CronScheduler {
	public static void main(String[] args) throws Exception {
		JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
				.withIdentity("myJob").build();
		Trigger trigger = TriggerBuilder.newTrigger()
				.withIdentity("cronTrigger")
				//cron表达式 这里定义的是4月16日早上9点21分开始执行
				.withSchedule(CronScheduleBuilder.cronSchedule("0 21 9 16 4 ? *"))
				.build();
		SchedulerFactory factory = new StdSchedulerFactory();
		//创建调度器
		Scheduler scheduler = factory.getScheduler();
		//启动调度器
		scheduler.start();
		//jobDetail和trigger加入调度
		scheduler.scheduleJob(jobDetail, trigger);
	}
}


这里通过cron表达式确定时间规则


一般我们会使用

cron生成器

,地址是

http://cron.qqe2.com/


执行结果如下


现在时间是:2019-04-16 09:21:00:开始执行任务生成表格,或者发送邮件

Quartz的3大API

Job


JobDetail & Job & JobDataMap


JobDetail

是任务的定义,而

Job

是任务的执行逻辑。在JobDetail里会引用一个Job Class定义。每一个JobDetail都会有一个

JobDataMap

。JobDataMap本质就是一个Map的扩展类,只是提供了一些更便捷的方法,比如getString()之类的。

public class CronScheduler {
	public static void main(String[] args) throws Exception {
		JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
				//添加jobname,jobgroup
				.withIdentity("myJob","myGroup")
				//jobDataMap信息
				.usingJobData("message","this is a message")
				.build();
		Trigger trigger = TriggerBuilder.newTrigger()
				.withIdentity("cronTrigger")
				//cron表达式 这里定义的是4月16日早上9点21分开始执行
				.withSchedule(CronScheduleBuilder.cronSchedule("0 00 10 16 4 ? *"))
				.build();
		SchedulerFactory factory = new StdSchedulerFactory();
		//创建调度器
		Scheduler scheduler = factory.getScheduler();
		//启动调度器
		scheduler.start();
		//jobDetail和trigger加入调度
		scheduler.scheduleJob(jobDetail, trigger);
	}
}
public class HelloJob implements Job{
	private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	@Override
	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
		Date now = new Date();
		String currentDate = sdf.format(now);
		JobDetail jobDetail = jobExecutionContext.getJobDetail();
		JobDataMap jobDataMap = jobDetail.getJobDataMap();
		JobKey jobKey = jobDetail.getKey();
		String jobName = jobKey.getName();
		String group = jobKey.getGroup();
		String message = (String) jobDataMap.get("message");
		System.out.println("现在时间是:"+currentDate+":开始执行任务生成表格,或者发送邮件");
		System.out.println("jobName---"+jobName);
		System.out.println("group---"+group);
		System.out.println("message---"+message);
	}
}
现在时间是:2019-04-16 10:00:00:开始执行任务生成表格,或者发送邮件
jobName---myJob
group---myGroup
message---this is a message

Tigger


1.startTime和endTime

有时候我们希望一个定时任务在一定的时间内是每天执行,比如2017年11月24日到2017年12月15日之间执行,这时候我们就要使用startTime和endTime来限定事件范围了。例子中我们把时间规定在几秒钟之内运行,方便查看效果。

public class HelloJob implements Job{
	private static final SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		Date now = new Date();
		String currentTime = sdf.format(now);
		System.out.println("执行时间为:"+currentTime);
	}
}
public class HelloScheduler {
	public static void main(String[] args) throws SchedulerException {
		//创建jobDetail绑定HelloJob
		JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
						.withIdentity("myJob","myGroup").build();
		//设定开始时间,结束时间确定范围
		Date triggerStartTime = new Date();
		//3秒后开始执行
		triggerStartTime.setTime(triggerStartTime.getTime()+3000);
		Date triggerEndTime = new Date();
		//10秒后结束执行
		triggerEndTime.setTime(triggerEndTime.getTime()+10000);
		//创建触发器trigger每个2秒执行一次,一直执行
		Trigger trigger = TriggerBuilder.newTrigger().withIdentity("mtTrigger", "myGroup")
						.startAt(triggerStartTime)
						.endAt(triggerEndTime)
						.withSchedule(SimpleScheduleBuilder.simpleSchedule()
						.withIntervalInSeconds(2).repeatForever()).build();
		//创建调度者工厂
		SchedulerFactory schedulerFactory = new StdSchedulerFactory();
		//创建调度者
		Scheduler scheduler = schedulerFactory.getScheduler();
		//启动调度器
		scheduler.start();
		//设置调度任务
		scheduler.scheduleJob(jobDetail, trigger);
	}
}

3秒后执行,10秒内结束执行

如下

执行时间为:2019-04-16 10:36:09
执行时间为:2019-04-16 10:36:11
执行时间为:2019-04-16 10:36:13
执行时间为:2019-04-16 10:36:15


2.BaseCalndar

此calendar不是java.util.Calendar,calendar是为了补充Trigger的时间,可以排除或加入一下特定的时间。Quartz 的 Calender 专门用于屏闭一个时间区间,使 Trigger 在这个区间中不被触发。

  1. AnnualCalendar:排除每一年中指定的一天或者多少天 ,精度是天
  2. CronCalendar:使用表达式排除某些时间段不执行,精度取决于Cron表达式,最大精度到秒
  3. DailyCalendar:指定的时间范围内的每一天不执行,指定每天的时间段,格式是HH:MM[:SS[:mmm]]。也就是最大精度可以到毫秒。
  4. HolidayCalendar:排除节假日,精度到天
  5. MonthlyCalendar:排除月份中的数天,可选值为1-31。精度是天
  6. WeeklyCalendar:排除星期中的一天或多天,可选值比如为java.util.Calendar.SUNDAY,精度是天。

这里使用CronCalendar排除

public class HelloJob implements Job{
	private static final SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		Date now = new Date();
		String currentTime = sdf.format(now);
		System.out.println("执行时间为:"+currentTime);
	}
}
public class HelloScheduler {
	public static void main(String[] args) throws SchedulerException, ParseException {
		//创建jobDetail绑定HelloJob
		JobDetail jobDetail = JobBuilder.newJob(HelloJob.class)
						.withIdentity("myJob","myGroup").build();
		//创建触发器trigger每个2秒执行一次,一直执行
		Trigger trigger = TriggerBuilder.newTrigger().withIdentity("mtTrigger", "myGroup")
				.withSchedule(SimpleScheduleBuilder.simpleSchedule()
						.withIntervalInSeconds(2).repeatForever())
				//将calendar排除规则绑定到触发器
				.modifiedByCalendar("myCalendar")
				.build();
		//创建调度者工厂
		SchedulerFactory schedulerFactory = new StdSchedulerFactory();
		//创建调度者
		Scheduler scheduler = schedulerFactory.getScheduler();
		CronCalendar calendar = new CronCalendar("* * 0-12,18-23 ? * *");
		//向Scheduler注册日历
		scheduler.addCalendar("myCalendar", calendar, false, false);
		//启动调度器
		scheduler.start();
		//设置调度任务
		scheduler.scheduleJob(jobDetail, trigger);
	}
}
11:39:12.270 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers
11:39:12.381 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 0 triggers

上面指定的是0-12 18-23不执行发现12点之前没有执行

Trigger的实现类


1CalendarIntervalTrigger




是一个具体的Trigger,用来触发基于定时重复的JobDetail。

Trigger将会每隔N个calendar在trigger中定义的时间单元触发一次。这个trigger不适合使用SimpleTrigger完成(例如由于每一个月的时间不是固定的描述),也不适用于CronTrigger(例如每5个月)。

相较于SimpleTrigger有两个优势:1、更方便,比如每隔1小时执行,你不用自己去计算1小时等于多少毫秒。 2、支持不是固定长度的间隔,比如间隔为月和年。但劣势是精度只能到秒。

它适合的任务类似于:9:00 开始执行,并且以后每周 9:00 执行一次

它的属性有:

  • interval 执行间隔
  • intervalUnit 执行间隔的单位(秒,分钟,小时,天,月,年,星期)
CalendarIntervalScheduleBuilder
     .calendarIntervalSchedule()
     .withIntervalInDays(1)  //每天执行一次
   //.withIntervalInHours(1)
   //.withIntervalInMinutes(1)
   //.withIntervalInMonths(1)
   //.withIntervalInSeconds(1)
   //.withIntervalInWeeks(1)
   //.withIntervalInHours(1)
     .build()

2DailyTimeIntervalTrigger

指定每天的某个时间段内,以一定的时间间隔执行任务。并且它可以支持指定星期。

它适合的任务类似于:指定每天9:00 至 18:00 ,每隔70秒执行一次,并且只要周一至周五执行。

它的属性有:

  • startTimeOfDay 每天开始时间
  • endTimeOfDay 每天结束时间
  • daysOfWeek 需要执行的星期
  • interval 执行间隔
  • intervalUnit 执行间隔的单位(秒,分钟,小时,天,月,年,星期)
  • repeatCount 重复次数
public static void main(String[] args) throws SchedulerException {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //1.创建一个jobDetail的实例,将该实例与HelloJob Class绑定
        JobDetail jobDetail = JobBuilder
                .newJob(HelloJob.class)
                .withIdentity("myJob", "group1") //定义name 和 group
                .build();

        //2.创建一个Trigger触发器的实例
        Trigger simpleTrigger = TriggerBuilder.newTrigger()
                .withIdentity("zhlTrigger")
                .withSchedule(
                        DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()
                                .startingDailyAt(TimeOfDay.hourAndMinuteOfDay(8, 0)) //每天8:00开始
                                .endingDailyAt(TimeOfDay.hourAndMinuteOfDay(17, 0)) //17:00 结束
                                .onDaysOfTheWeek(MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY) //周一至周五执行
                                .withIntervalInHours(1) //每间隔1小时执行一次
                                .withRepeatCount(100) //最多重复100次(实际执行100+1次)
                )
                .modifiedByCalendar("holidays")   //将我们设置好的Calander与trigger绑定
                .build();

        //3.创建schedule实例
        StdSchedulerFactory factory = new StdSchedulerFactory();
        Scheduler scheduler = factory.getScheduler();
        System.out.println("现在的时间 :"+sf.format(new Date()));
        System.out.println();
        System.out.println("最近的一次执行时间 :"+sf.format(scheduler.scheduleJob(jobDetail,simpleTrigger))); //scheduler与jobDetail、trigger绑定,并打印出最近一次执行的事件
        scheduler.start();
    }


Scheduler

——工厂模式:

所有的Scheduler实例应该由SchedulerFactory来创建,一般包含:StdSchedulerFactory、DirectSchedulerFactory(参数信息需要在代码中维护故不常用)。

StdSchedulerFactory使用一组参数来创建和初始化Quartz调度器,配置参数一般存储在quartz.properties文件中,调用getScheduler方法就能创建和初始化调度器对象。

Scheduler的主要函数:


Data scheduleJob(JobDetail jobDetail,Trigger trigger);


void start();——启动Scheduler;


void standby();——将Scheduler暂时挂起,可以用start()继续执行任务;


void shutDown()关闭Scheduler且不能被重启;示例代码如下:



版权声明:本文为baiyan3212原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。