Java Quartz 任務調度

目錄

1.Quartz的作用

定時自動執行任務

2.預備

相關包:http://www.quartz-scheduler.org/
quartz2.2.1
quartz-jobs2.2.1
POM文件:

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

3.Quartz核心

3.1.Job接口
被調度的任務,只有一個方法execute(JobExecutionContext xontext),Job運行時的信息保存在JobDataMap中

3.2.JobDetail類
實現Job接口,用來描述Job的相關信息,包含Name,Group,JobDataMap等

3.3 JobExecutionContext類
定時程序執行的run-time的上下文環境,用於得到Job的名字、配置的參數等

3.3 JobDataMap類
用來描述一個作業的參數,參數可以爲金和基本類型或者某個對象的引用

3.3 JobListener接口
監聽作業狀態

3.3 TriggaerListener接口
監聽觸發器狀態

3.3 JobStore
3.3.Tigger抽象類
觸發器,描述執行Job的觸發規則,有SimpleTrigger和CronTrigger兩個子類

3.3.1.SimpleTrigger類
繼承自Trigger類,每隔xx毫秒/秒執行一次,主要實現固定一次或者固定時間週期類任務的觸發

3.3.2.CronTrigger類
繼承自Trigger類,使用Cron表達式,實現各種複雜時間規則調度方案,如每天的某個時間,或每週的某幾天觸發執行之類

3.4.Calendar包
一些日曆特定時間點的集合,包內包含以下幾個類

3.4.1 BaseCalendar類
3.4.2 AnnualCalendar類
排除每一年中指定的一天或者多天

3.4.3 CalendarComparator類
3.4.4 CronCalendar類
使用表達式排除某時間段不執行

3.4.5 DailyCalendar類
指定的時間範圍內每天不執行

3.4.6 HolidayCalendar類
排除節假日

3.4.7 MonthlyCalendar類
配出月份中的數天

3.4.8 WeeklyCalendar類
排除沒週中的一天或者多天

3.5.Scheduler類
任務調度器,代表一個Quartz獨立容器。

Scheduler可以將JobDetail和Trigger綁定,當Trigger觸發時,對應的Job就會被執行,Job和Trigger是1:n(一對多)的關係

3.6Misfire類
錯誤的任務,本該執行單沒有執行的任務調度

4.實現

4.1 單任務實現
1.定義一個任務,新建任務類繼承自Job類

package com;

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

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

public class DemoJob implements Job {

	@Override
	public void execute(JobExecutionContext arg0) throws JobExecutionException {
		System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date()));
	}

}

2.新建類執行這個任務(SimpleTrigger)

package com;

import java.util.Date;

import org.quartz.DateBuilder;
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;

public class QuartzDemo {

	public void simpleRun() throws SchedulerException {
		// 創建一個調度器工廠
		SchedulerFactory factory = new StdSchedulerFactory();

		 //任務執行時間  
		//Date runTime = DateBuilder.evenMinuteDate(new Date());  
	    Date runTime = DateBuilder.evenSecondDateAfterNow();  

		// 新建JobDetail對象並綁定一個任務
		JobDetail jobDetail = JobBuilder.newJob(DemoJob.class)
				.withIdentity("demo_job", "demo_group")
				.build();
		// 定義調度規則
		Trigger trigger = TriggerBuilder.newTrigger()
				.withIdentity("demo_trigger", "demo_group")
				//.startNow()//立即執行
				.startAt(new Date())//設置觸發開始的時間
				.withSchedule(
						SimpleScheduleBuilder
						.simpleSchedule()
						.withIntervalInSeconds(1)//時間間隔
						.withRepeatCount(5)//重複次數(n+1),比如這裏將執行6次
				).build();//生成觸發器

		// 從工廠獲取一個調度器對象
		Scheduler scheduler = factory.getScheduler();
		//綁定觸發器和任務
		scheduler.scheduleJob(jobDetail,trigger);
		System.out.println(jobDetail.getKey() + " 運行在: " + runTime);   
		scheduler.start();  
	}

	public static void main(String[] args) {
		QuartzDemo demo = new QuartzDemo();
		try {
			demo.simpleRun();
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}
}

4.2多任務實現
4.2.1 測試任務類
新建兩個DemoJonOne和DemoJobTwo,都實現Job接口,內容如下

@Override
	public void execute(JobExecutionContext arg0) throws JobExecutionException {
		System.out.println(new SimpleDateFormat("HH:mm:ss").format(new Date())+" Runed "+getClass().getName());
	}

4.42 新建QuartzUtil類,內容如下

package com;

import org.quartz.Job;
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;

public class QuartzUtil {
	private final static String JOB_GROUP_NAME = "QUARTZ_JOBGROUP_NAME";// 任務組
	private final static String TRIGGER_GROUP_NAME = "QUARTZ_TRIGGERGROUP_NAME";// 觸發器組

	/**
	 * 添加任務的方法
	 *
	 * @param jobName 任務名
	 * @param triggerName 觸發器名
	 * @param jobClass 執行任務的類
	 * @param seconds 間隔時間
	 * @throws SchedulerException
	 */
	public static void addJob(String jobName, String triggerName, Class<? extends Job> jobClass, int seconds)
			throws SchedulerException {

		// 創建一個SchedulerFactory工廠實例
		SchedulerFactory sf = new StdSchedulerFactory();
		// 通過SchedulerFactory構建Scheduler對象
		Scheduler sche = sf.getScheduler();
		// 用於描述Job實現類及其他的一些靜態信息,構建一個作業實例
		JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, JOB_GROUP_NAME).build();
		// 構建一個觸發器,規定觸發的規則
		Trigger trigger = TriggerBuilder.newTrigger()// 創建一個新的TriggerBuilder來規範一個觸發器
				.withIdentity(triggerName, TRIGGER_GROUP_NAME)// 給觸發器起一個名字和組名
				.startNow()// 立即執行
				.withSchedule(
						SimpleScheduleBuilder
						.simpleSchedule()
						.withIntervalInSeconds(seconds)// 時間間隔																// 單位:秒
						.repeatForever()// 一直執行
				).build();// 產生觸發器

		//綁定觸發器和任務
		sche.scheduleJob(jobDetail, trigger);
		// 啓動
		sche.start();
	}

	public static void main(String[] args) {
		try {
			// 添加第一個任務 每隔10秒執行一次
			QuartzUtil.addJob("job1", "trigger1", DemoJobOne.class, 2);

			// 添加第二個任務 每隔20秒執行一次
			QuartzUtil.addJob("Job2", "trigger2", DemoJobTwo.class, 5);
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}
}

以上方法屬於手動調用,如果是web項目中就不同了
添加POM

<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
</dependency>

1.創建servlet

package servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;

import org.quartz.SchedulerException;

import com.DemoJobOne;
import com.DemoJobTwo;
import com.QuartzUtil;

public class InitServlet extends HttpServlet {

	private static final long serialVersionUID = 8507188690597926975L;

	/**
	 * 因爲我們不需要處理請求與響應的消息操作,所以這個地方只留一個初始化的操作就行了,用以執行任務調度的入口
	 */
	public void init() throws ServletException {
		try {
			// 添加第一個任務 每隔2秒執行一次
			QuartzUtil.addJob("job1", "trigger1", DemoJobOne.class, 2);
			// 添加第二個任務 每隔5秒執行一次
			QuartzUtil.addJob("Job2", "trigger2", DemoJobTwo.class, 5);
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}

}

2.註冊servlet

<servlet>
  <servlet-name>InitServlet</servlet-name>
  <servlet-class>servlet.InitServlet</servlet-class>
  <!-- 設置優先級 -->
  <load-on-startup>0</load-on-startup>
</servlet>

<servlet-mapping>
  <servlet-name>InitServlet</servlet-name>
  <url-pattern>/InitServlet</url-pattern>
</servlet-mapping>

3.複雜規則任務調度(CronTrigger)
在每分鐘的1-30秒執行示例

package com;

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

public class CronTriggerDemo {
	public static void main(String[] args) throws SchedulerException {

		SchedulerFactory factory = new StdSchedulerFactory();
		Scheduler scheduler = factory.getScheduler();

		JobDetail job = JobBuilder
				.newJob(DemoJobOne.class)
				.withIdentity("job","group")
				.build();

		Trigger trigger = TriggerBuilder
				.newTrigger()
				.withIdentity("trigger", "group")
				.startNow().withSchedule(
						CronScheduleBuilder
						.cronSchedule("1-30 * * * * ?")
				).build();

		scheduler.scheduleJob(job,trigger);
		scheduler.start();

	}
}

4.Cron表達式
規則:
s M h d m w [y]
s:seconds,取值0-59,允許- * /;

M:minutes,取值0-59,允許- * /;

h:hour,取值0-23,允許- * /;

d:day of month,取值1-31,允許- * ? / L W;

m:month,取值1-12/JAN-DEC,允許- * /;

w:day of week,取值1-7/SUN-SAT,允許- * ? / L #;

y:year,可選,取值empty、1970-2099,允許- * /;

符號解釋
、 指定枚舉值,如在秒字段使用10、12,則表示只有第10秒和第12秒執行

  • 指定區間範圍,配合使用,如在小時字段使用10-12,表示在10、11、12時都會觸發
  • 代表所有值,單獨使用,如在秒字段使用,表示每秒觸發

? 代表不確定值,單獨使用,不用關心的值

/ 用於遞增觸發,配合使用,n/m,從n開始,每次增加m,如在秒字段設置5/15,表示從第5秒開始,每15秒觸發一次

L 表示最後,單獨使用,如在秒字段使用,代表第59秒觸發,如果在前面加上數字,則表示該數據的最後一個,如在周字段使用6L,則表示本月最後一個週五
W 表示最近的工作日,不會跨月,比如30W,30號是週六,則不會順延至下週一來執行,如在月字段使用15W,則表示到本月15日最近的工作日(週一到週五)
#用來指定x的第n個工作日,如在周字段使用6#3則表示該月的第三個星期五

月取值
一月:JAN/0
二月:FEB/1
三月:MAR/2
四月:APR/3
五月:MAY/4
六月:JUN/5
七月:JUL/6
八月:AUG/7
九月:SEP/8
十月:OCT/9
十一月:NOV/10
十二月:DEC/11

周取值
週日:SUN/1
週一:MON/2
週二:TUE/3
週三:WED/4
週四:THU/5
週五:FRI/6
週六:SAT/7

示例
0/20 * * * * ? 每20秒執行一次
1-30 * * * * ? 在1-30秒執行
15 0/2 * * * ? 偶數分鐘的第15秒執行
0 0/2 8-17 * * ? 從8時到17時 ,每個偶數分鐘執行一次
0 0/3 17-23 * * ? 從17時到23時,每3分鐘運行一次
0 0 10am 1,15 * ? 每個月的1號和15號的上午10點 運行
0,30 * * ? * MON-FRI 週一至週五,每30秒運行一次
0,30 * * ? * SAT,SUN 週六、週日,每30秒運行一次
0 0 12 * * ? 每天12點觸發
0 15 10 ? * * 每天10點15分觸發
0 15 10 * * ? 每天10點15分觸發
0 15 10 * * ? * 每天10點15分觸發
0 15 10 * * ? 2005 2005年每天10點15分觸發
0 * 14 * * ? 每天下午的 2點到2點59分每分觸發
0 0/5 14 * * ? 每天下午的 2點到2點59分(整點開始,每隔5分觸發)
0 0/5 14,18 * * ? 每天下午的 2點到2點59分(整點開始,每隔5分觸發) 每天下午的 18點到18點59分(整點開始,每隔5分觸發)
0 0-5 14 * * ? 每天下午的 2點到2點05分每分觸發
0 10,44 14 ? 3 WED 3月分每週三下午的 2點10分和2點44分觸發
0 15 10 ? * MON-FRI 從週一到週五每天上午的10點15分觸發
0 15 10 15 * ? 每月15號上午10點15分觸發
0 15 10 L * ? 每月最後一天的10點15分觸發
0 15 10 ? * 6L 每月最後一週的星期五的10點15分觸發
0 15 10 ? * 6L 2002-2005 從2002年到2005年每月最後一週的星期五的10點15分觸發
0 15 10 ? * 6#3 每月的第三週的星期五開始觸發
0 0 12 1/5 * ? 每月的第一個中午開始每隔5天觸發一次
0 11 11 11 11 ? 每年的11月11號 11點11分觸發(光棍節)
5.Spring整合Quartz
需要Spring-context-support包支持,POM如下

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.3.5.RELEASE</version>
</dependency>

新建兩種Job測試類–>DemoSimpleJob類和DemoCronJob類,並繼承自QuartzJobBean,代碼如下

package com;

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

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class DemoJob extends QuartzJobBean {

    @Override
    protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
        System.out.println(new SimpleDateFormat("hh:mm:ss").format(new Date()) + " 輸出自:" + getClass().getName());
    }

}

配置spring bean如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.3.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <!--org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean -->
    
    <!-- 配置任務 -->
    <bean id="demoCronJob"
        class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.DemoCronJob" />
    </bean>
    <bean id="demoSimpleJob"
        class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.DemoSimpleJob" />
    </bean>
    <!-- <property name="jobDataAsMap"> -->
    <!-- 配置觸發器 -->
    <bean id="simpleTrigger"
        class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
        <property name="jobDetail" ref="demoSimpleJob" />
        <property name="startDelay" value="1000" />  
        <property name="repeatInterval" value="2000" />  
    </bean>
    <bean id="cornTrigger"
        class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="demoCronJob" />
        <property name="cronExpression" value="1-30 * * * * ?" />
    </bean>
    <!-- 配置調度器 -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="cornTrigger" />
                <ref bean="simpleTrigger" />
            </list>
        </property>
    </bean>

啓動

package com;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Demo {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章