項目中使用分布式並發部署定時任務,多台跨JVM,按照常理邏輯每個JVM的定時任務會各自運行,這樣就會存在問題,多台分布式JVM機器的應用服務同時干活,一個是加重服務負擔,另外一個是存在嚴重的邏輯問題,比如需要回滾的數據,就回滾了多次,剛好quartz提供很好的解決方案。
集群分布式並發環境中使用QUARTZ定時任務調度,會在各個節點會上報任務,存到數據庫中,執行時會從數據庫中取出觸發器來執行,如果觸發器的名稱和執行時間相同,則只有一個節點去執行此任務。
如果此節點執行失敗,則此任務則會被分派到另一節點執行,中途也會自動檢查失效的定時調度,發現不成功的,其他節點立馬接過來繼續完成定時任務。對應的定時任務調度表比較多,有11個。
后續功能:
准備code一個web調度工作台,對所有job進行統計管理和監控;
引入依賴:
<!-- quartz -->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
配置quartz數據庫:
官網下載,tz壓縮包,在解壓目錄docs\dbTables下找到對應的執行sql,執行即可;
配置本地quartz.properties:
單機版,使用RAMJobStore存儲任務,可以使用jar包總默認配置,改方式執行最迅速,強大,方便;
集群版本,需要copy出jar包中配置,新增如下配置,並注釋掉重復配置項目,即可;
# for cluster
org.quartz.scheduler.instanceId: AUTO
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.isClustered: true
org.quartz.jobStore.clusterCheckinInterval: 1000
創建CronTrigger和JobDetail,二者為包含關系:
Quartz2.0創建JobDetail有兩種方式:
方式一:CronTrigger包含JobDetail,JobDetail用MethodInvokingJobDetailFactoryBean工廠Bean包裝普通的Java對象或bean;
<!-- Job trigger -->
<bean id="job01Trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" >
<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="jobService" />
<property name="targetMethod" value="job01" />
<property name="concurrent" value="false" />
</bean>
</property>
<property name="cronExpression" value="0/3 * * * * ? *" />
</bean>
方式二:CronTrigger包含JobDetail,JobDetail用JobDetailFactoryBean包裝QuartzJobBean的繼承子類(即Job類)的實例;
<!-- Job trigger -->
<bean id="job02Trigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" >
<bean class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.xxl.job.JobDetailDemo"/>
<property name="jobDataAsMap">
<map>
<!-- <entry key="xxService" value-ref="xxService" /> -->
</map>
</property>
<property name="durability" value="true"></property>
</bean>
</property>
<property name="cronExpression" value="0/1 * * * * ? *" />
</bean>
創建調度工廠,根據數據存儲方式,分為兩種:
方式一:內存RAMJobStore:把job的相關信息存儲在內存里,如果用spring配置quartz的job信息的話,所有信息是配置在xml里,當spirng context啟動的時候就把xml里的job信息裝入內存。
<bean name="startQuertz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="job01Trigger" />
</list>
</property>
</bean>
方式二:數據庫:讀取配置在數據庫里的job初始化信息,並且把job通過java序列化到數據庫里,這樣就使得每個job信息得到了持久化,即使在jvm或者容器掛掉的情況下,也能通過數據庫感知到其他job的狀態和信息;quartz集群各節點之間是通過同一個數據庫實例(准確的說是同一個數據庫實例的同一套表)來感知彼此的。
<bean id="quartzScheduler" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="autoStartup" value="true" />
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<property name="configLocation" value="classpath:quartz.properties"/>
<property name="triggers">
<list>
<ref bean="job02Trigger" />
</list>
</property>
</bean>
tips:applicationContextSchedulerContextKey: 是org.springframework.scheduling.quartz.SchedulerFactoryBean這個類中把spring上下 文以key/value的方式存放在了quartz的上下文中了,可以用applicationContextSchedulerContextKey所定義的key得到對應的spring上下文。
實例應用:
..
..
