一、序言
1、你瞭解 Quartz 嗎?
Quartz 是一個完全由 Java 編寫的開源作業調度框架,爲在 Java 應用程序中進行作業調度提供了簡單卻強大的機制。
Quartz 可以與 J2EE 與 J2SE 應用程序相結合也可以單獨使用。
Quartz 允許程序開發人員根據時間的間隔來調度作業。
Quartz 實現了作業和觸發器的多對多的關係,還能把多個作業與不同的觸發器關聯。
2、Quartz 核心概念
我們需要明白 Quartz 的幾個核心概念,這樣理解起 Quartz 的原理就會變得簡單了。
1、Job 表示一個工作,要執行的具體內容。此接口中只有一個方法,如下:
void execute(JobExecutionContext context)
2、JobDetail 表示一個具體的可執行的調度程序,Job 是這個可執行程調度程序所要執行的內容,另外 JobDetail 還包含了這個任務調度的方案和策略。
3、Trigger 代表一個調度參數的配置,什麼時候去調。
4、Scheduler 代表一個調度容器,一個調度容器中可以註冊多個 JobDetail 和 Trigger。當 Trigger 與 JobDetail 組合,就可以被 Scheduler 容器調度了。
3、Quartz的運行環境
1、Quartz 可以運行嵌入在另一個獨立式應用程序。
2、Quartz 可以在應用程序服務器(或 servlet 容器)內被實例化,並且參與 XA 事務。
3、Quartz 可以作爲一個獨立的程序運行(其自己的 Java 虛擬機內),可以通過 RMI 使用。
4、Quartz 可以被實例化,作爲獨立的項目集羣(負載平衡和故障轉移功能),用於作業的執行。
4、Quartz的集羣功能
Quartz的集羣功能通過故障轉移和負載平衡功能爲您的調度程序帶來高可用性和可擴展性。
目前,羣集僅適用於JDBC-Jobstore(JobStoreTX或JobStoreCMT),並且基本上通過使羣集的每個節點共享相同的數據庫來工作。
負載平衡自動發生,羣集的每個節點都儘可能快地觸發jobs。當Triggers的觸發時間發生時,獲取它的第一個節點(通過在其上放置一個鎖定)是將觸發它的節點。
每次射擊只能有一個節點開火。我的意思是,如果工作有一個重複的Triggers,告訴它每10秒鐘發射一次,那麼在12:00:00,正好一個節點將運行這個工作,在12:00:10,一個節點將運行作業等。它不一定是每次相同的節點 - 它或多或少是隨機的,哪個節點運行它。負載平衡機制對於繁忙的調度器(大量的Triggers)是近似隨機的,但是對於非忙(例如,很少的Triggers)調度器而言,有利於同一個節點。
當其中一個節點在執行一個或多個作業期間失敗時發生故障切換。當節點出現故障時,其他節點會檢測到該狀況並識別數據庫中在故障節點內正在進行的作業。任何標記爲恢復的作業(在JobDetail上都具有“請求恢復”屬性)將被剩餘的節點重新執行。沒有標記爲恢復的作業將在下一次相關的Triggers觸發時簡單地被釋放以執行。
集羣功能最適合擴展長時間運行和/或cpu密集型作業(通過多個節點分配工作負載)。如果需要擴展以支持數千個短期運行(例如1秒)作業,則可以考慮通過使用多個不同的調度程序(包括HA的多個羣集調度程序)對作業集進行分區。調度程序使用集羣範圍的鎖,這種模式會在添加更多節點(超過三個節點 - 取決於數據庫的功能等)時降低性能。
通過將“org.quartz.jobStore.isClustered”屬性設置爲“true”來啓用聚類。集羣中的每個實例都應該使用相同的quartz.properties文件。這樣做的例外是使用相同的屬性文件,具有以下允許的異常:不同的線程池大小,以及“org.quartz.scheduler.instanceId”屬性的不同值。集羣中的每個節點必須具有唯一的instanceId,通過將“AUTO”作爲此屬性的值,可以輕鬆完成(不需要不同的屬性文件)。有關更多信息,請參閱有關JDBC-JobStore的配置屬性的信息。
不要在單獨的機器上運行羣集,除非它們的時鐘使用某種形式的時間同步服務(守護進程)進行同步,而這些時間同步服務(守護進程)運行非常有限(時鐘必須在彼此之間)。
不要針對任何其他實例運行(start()ed)的同一組數據庫表啓動(scheduler.start())非集羣實例。您可能會收到嚴重的數據損壞,一定會遇到不正常的行爲。
二、下載安裝
1、首先需要下載jar包,本文以2.2.3版本爲例,官方下載地址:http://www.quartz-scheduler.org/downloads/
注:如果是maven工程則可使用下面的配置:
<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>
2、下載後的解壓的目錄
3、項目使用有可能會用到lib目錄下的包,如果是maven項目,自己在pom.xml中添加依賴的jar包,下面是lib目錄中所有的jar包:
三、集羣配置
1、持久化需要使用到數據庫,quartz提供了各種數據庫的腳本。腳本文件放在quartz-2.2.3-distribution.tar.gz\quartz-2.2.3\docs\dbTables目錄下,這裏以Mysql爲例(注:如果使用其他的數據庫則使用不同的Quartz數據庫腳本)。
下面爲mysql文件的具體數據庫腳本:
#
# In your Quartz properties file, you'll need to set
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#
#
# By: Ron Cordell - roncordell
# I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM.DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
DROP TABLE IF EXISTS QRTZ_LOCKS;
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
DROP TABLE IF EXISTS QRTZ_CALENDARS;CREATE TABLE QRTZ_JOB_DETAILS(
SCHED_NAME VARCHAR(120) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
IS_DURABLE VARCHAR(1) NOT NULL,
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
JOB_NAME VARCHAR(200) NOT NULL,
JOB_GROUP VARCHAR(200) NOT NULL,
DESCRIPTION VARCHAR(250) NULL,
NEXT_FIRE_TIME BIGINT(13) NULL,
PREV_FIRE_TIME BIGINT(13) NULL,
PRIORITY INTEGER NULL,
TRIGGER_STATE VARCHAR(16) NOT NULL,
TRIGGER_TYPE VARCHAR(8) NOT NULL,
START_TIME BIGINT(13) NOT NULL,
END_TIME BIGINT(13) NULL,
CALENDAR_NAME VARCHAR(200) NULL,
MISFIRE_INSTR SMALLINT(2) NULL,
JOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
REPEAT_COUNT BIGINT(7) NOT NULL,
REPEAT_INTERVAL BIGINT(12) NOT NULL,
TIMES_TRIGGERED BIGINT(10) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_CRON_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
CRON_EXPRESSION VARCHAR(120) NOT NULL,
TIME_ZONE_ID VARCHAR(80),
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_SIMPROP_TRIGGERS
(
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
STR_PROP_1 VARCHAR(512) NULL,
STR_PROP_2 VARCHAR(512) NULL,
STR_PROP_3 VARCHAR(512) NULL,
INT_PROP_1 INT NULL,
INT_PROP_2 INT NULL,
LONG_PROP_1 BIGINT NULL,
LONG_PROP_2 BIGINT NULL,
DEC_PROP_1 NUMERIC(13,4) NULL,
DEC_PROP_2 NUMERIC(13,4) NULL,
BOOL_PROP_1 VARCHAR(1) NULL,
BOOL_PROP_2 VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_BLOB_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
BLOB_DATA BLOB NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_CALENDARS (
SCHED_NAME VARCHAR(120) NOT NULL,
CALENDAR_NAME VARCHAR(200) NOT NULL,
CALENDAR BLOB NOT NULL,
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
ENGINE=InnoDB;CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
SCHED_NAME VARCHAR(120) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
ENGINE=InnoDB;CREATE TABLE QRTZ_FIRED_TRIGGERS (
SCHED_NAME VARCHAR(120) NOT NULL,
ENTRY_ID VARCHAR(95) NOT NULL,
TRIGGER_NAME VARCHAR(200) NOT NULL,
TRIGGER_GROUP VARCHAR(200) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
FIRED_TIME BIGINT(13) NOT NULL,
SCHED_TIME BIGINT(13) NOT NULL,
PRIORITY INTEGER NOT NULL,
STATE VARCHAR(16) NOT NULL,
JOB_NAME VARCHAR(200) NULL,
JOB_GROUP VARCHAR(200) NULL,
IS_NONCONCURRENT VARCHAR(1) NULL,
REQUESTS_RECOVERY VARCHAR(1) NULL,
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
ENGINE=InnoDB;CREATE TABLE QRTZ_SCHEDULER_STATE (
SCHED_NAME VARCHAR(120) NOT NULL,
INSTANCE_NAME VARCHAR(200) NOT NULL,
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
ENGINE=InnoDB;CREATE TABLE QRTZ_LOCKS (
SCHED_NAME VARCHAR(120) NOT NULL,
LOCK_NAME VARCHAR(40) NOT NULL,
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
ENGINE=InnoDB;CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);commit;
2、數據庫腳本導入完成之後,我們接下來需要對quartz進行一些配置,本文用spring來管理scheduler調度實例,spring管理配置的xml文件如下:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <!--<property name="applicationContextSchedulerContextKey" value="applicationContext"/>--> <property name="jobFactory"> <bean class="wade.core.interceptors.SpringBeanJobFactory"/> </property> <property name="dataSource"> <ref bean="dataSource"/> </property> <property name="configLocation" value="classpath:/conf/quartz.properties"/> </bean> </beans>
dataSouce的xml文件代碼爲:(本文使用的是C3P0連接池)
<!-- 配置連接池 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass"> <value>${jdbc.driverClassName}</value> </property> <property name="jdbcUrl"> <value>${jdbc.url}</value> </property> <property name="user"> <value>${jdbc.username}</value> </property> <property name="password"> <value>${jdbc.password}</value> </property> <!--初始化時獲取的連接數,取值應在minPoolSize與maxPoolSize之間。Default: 3 --> <property name="initialPoolSize"> <value>${c3p0.initialPoolSize}</value> </property> <!--連接池中保留的最小連接數。--> <property name="minPoolSize"> <value>${c3p0.minPoolSize}</value> </property> <!--連接池中保留的最大連接數。Default: 15 --> <property name="maxPoolSize"> <value>${c3p0.maxPoolSize}</value> </property> <!--最大空閒時間,60秒內未使用則連接被丟棄。若爲0則永不丟棄。Default: 0 --> <property name="maxIdleTime"> <value>${c3p0.maxIdleTime}</value> </property> <!--當連接池中的連接耗盡的時候c3p0一次同時獲取的連接數。Default: 3 --> <property name="acquireIncrement"> <value>${c3p0.acquireIncrement}</value> </property> <!--JDBC的標準參數,用以控制數據源內加載的PreparedStatements數量。但由於預緩存的statements 屬於單個connection而不是整個連接池。所以設置這個參數需要考慮到多方面的因素。 如果maxStatements與maxStatementsPerConnection均爲0,則緩存被關閉。Default: 0--> <property name="maxStatements"> <value>${c3p0.maxStatements}</value> </property> <!--每60秒檢查所有連接池中的空閒連接。Default: 0 --> <property name="idleConnectionTestPeriod"> <value>${c3p0.idleConnectionTestPeriod}</value> </property> <!--兩次連接中間隔時間,單位毫秒,默認爲1000 --> <property name="acquireRetryDelay"> <value>${c3p0.acquireRetryDelay}</value> </property> <!--定義在從數據庫獲取新連接失敗後重復嘗試的次數。Default: 30 --> <property name="acquireRetryAttempts"> <value>${c3p0.acquireRetryAttempts}</value> </property> <!--獲取連接失敗將會引起所有等待連接池來獲取連接的線程拋出異常。但是數據源仍有效 保留,並在下次調用getConnection()的時候繼續嘗試獲取連接。如果設爲true,那麼在嘗試 獲取連接失敗後該數據源將申明已斷開並永久關閉。Default: false--> <property name="breakAfterAcquireFailure"> <value>${c3p0.breakAfterAcquireFailure}</value> </property> <!--因性能消耗大請只在需要的時候使用它。如果設爲true那麼在每個connection提交的 時候都將校驗其有效性。建議使用idleConnectionTestPeriod或automaticTestTable 等方法來提升連接測試的性能。Default: false --> <property name="testConnectionOnCheckout"> <value>${c3p0.testConnectionOnCheckout}</value> </property> <!--c3p0是異步操作的,緩慢的JDBC操作通過幫助進程完成。擴展這些操作可以有效的提升性能 通過多線程實現多個操作同時被執行。Default: 3--> <property name="numHelperThreads"> <value>${c3p0.numHelperThreads}</value> </property> </bean>
quartz.properties配置文件的代碼爲:
#============================================================== #Configure Main Scheduler Properties #============================================================== org.quartz.scheduler.instanceName = quartzScheduler org.quartz.scheduler.instanceId = AUTO #============================================================== #Configure JobStore #============================================================== org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.tablePrefix = qrtz_ org.quartz.jobStore.isClustered = true org.quartz.jobStore.clusterCheckinInterval = 2000 org.quartz.jobStore.dataSource = myDS #============================================================== #Configure DataSource配置數據源 #============================================================== #org.quartz.dataSource.myDS.driver = oracle.jdbc.OracleDriver #org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@127.0.0.1/orcl #org.quartz.dataSource.myDS.user = dcap #org.quartz.dataSource.myDS.password = dcap#2018 #org.quartz.dataSource.myDS.maxConnections = 30 #============================================================== #Configure ThreadPool #============================================================== org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 20 org.quartz.threadPool.threadPriority = 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
注:本文的spring.xml的配置詳解將在我的其他的quartz文章裏詳細解釋。
3、創建兩個job測試定時任務。
(1)在自定義的controller類裏注入SchedulerFactoryBean(調度程序工程),此SchedulerFactoryBean已經被上文的xml引入,自動生成在spring的IOC容器中。
/** * 注入-調度程序工廠bean */ @Autowired private SchedulerFactoryBean schedulerFactoryBean;(2)
(2) 在自定義的controller類裏定義創建兩個job的方法(紅色的quartzService在我的quartz其他文章會有源碼和解釋貼出來,它quartzService也是通過注入方式)
@Resource public QuartzService quartzService;
@RequestMapping(params = "addJobone") @ResponseBody public AjaxJson addJob1(HttpServletRequest request) { try { Scheduler scheduler = schedulerFactoryBean.getScheduler(); quartzService.addJob("job1","default", (Class<? extends Job>) Class.forName("wade.system.job.TestJob"),"0 0/1 * * * ? ",null,scheduler,false,false); }catch (Exception e){ System.out.println(e); } return new AjaxJson(); } @RequestMapping(params = "addJobtwo") @ResponseBody public AjaxJson addJob2(HttpServletRequest request){ try { Scheduler scheduler = schedulerFactoryBean.getScheduler(); quartzService.addJob("job2","default", (Class<? extends Job>) Class.forName("wade.system.job.TestJob2"),"0 0/1 * * * ? ",null,scheduler,false,false); }catch (Exception e){ System.out.println(e); } return new AjaxJson(); }
(3)兩個job分別都要實現job接口,複寫execute()方法,當調度程序調度job任務時,就會執行execute裏的方法內容。
package wade.system.job; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; public class TestJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("job1運行"); } }
package wade.system.job; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; public class TestJob2 implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("job2運行"); } }
四、集羣實驗
(1)啓動項目,出現以下信息則啓動成功。
(2)調度器增加了兩個job任務,即調用上文的自定義controller類的創建兩個job的方法,作業名稱分別爲job1和job2.
(3)觀察tomcatA的運行情況,我們可發現job1和job2都是每一分鐘執行一次,這和我們上面配置的cron表達式一致。
(4)關鍵的集羣測試步驟來了,我們打開另一個tomcatB運行相同的項目,觀察現象。
tomcatA的控制輸出臺:
tomcatB的控制輸出臺:
實驗總結:我們能夠發現兩臺集羣的服務器都會共同執行job任務,當然同一個job在一個時間點只會執行一次,只是有時候由TomcatA執行,有時候由TomcatB執行,這樣就實現了集羣,分擔了tomcat的壓力。而且當TomcatA發生故障掛掉的時候,TomcatB能夠正常執行job任務,不會使得調度系統也掛掉,不過此時TomcatB承擔所有的job的調度任務。