喜歡從業(yè)的專注栗菜,七分學(xué)習(xí)的態(tài)度欠雌。
概述
Java項(xiàng)目定時(shí)任務(wù)(JOB)首選quartz,一般我們選擇集成到Spring中變成Spring+Quartz疙筹。拋開(kāi)API和復(fù)雜的部署邏輯富俄,簡(jiǎn)述簡(jiǎn)單配置經(jīng)驗(yàn)。 根據(jù)實(shí)際部署情況需要區(qū)分:?jiǎn)为?dú)環(huán)境而咆,集群環(huán)境霍比。
單獨(dú)環(huán)境:只有一臺(tái)機(jī)器運(yùn)行JOB,不存在任務(wù)沖突和搶任務(wù)問(wèn)題暴备。
集群環(huán)境:存在多個(gè)機(jī)器多個(gè)應(yīng)用服務(wù)器悠瞬,每個(gè)應(yīng)用都會(huì)運(yùn)行JOB,產(chǎn)生任務(wù)、事物搶占等一系列資源沖突問(wèn)題浅妆,在集群環(huán)境下需要保證多個(gè)應(yīng)用服務(wù)器中同一時(shí)間只有一個(gè)應(yīng)用服務(wù)運(yùn)行JOB望迎。
原理簡(jiǎn)述
-
配置步驟
要配置一個(gè)能執(zhí)行任務(wù)類的JOB分為三部分,配置JOB內(nèi)容凌外、配置執(zhí)行JOB的觸發(fā)器辩尊、配置觸發(fā)器管理工廠。
-
配置JOB內(nèi)容
配置一個(gè)bean康辑,用來(lái)指定Job需要運(yùn)行的類和方法对省。具體在Spring的xml中配置,區(qū)分單獨(dú)環(huán)境和集群環(huán)境晾捏。單獨(dú)環(huán)境
配置 一個(gè)job執(zhí)行 deviceActivatedService 的execute 方法:
<bean id="deviceActivateGetResultJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="deviceActivatedService"/>
</property>
<property name="targetMethod">
<value>execute</value>
</property>
<property name="concurrent" value="false"/>
</bean>集群環(huán)境
集群環(huán)境需要將JOB持久化蒿涎,才能實(shí)現(xiàn)集群中唯一執(zhí)行。就是將JOB信息寫(xiě)入到數(shù)據(jù)庫(kù)表中惦辛,Quartz利用自帶創(chuàng)建表腳本自動(dòng)創(chuàng)建對(duì)應(yīng)需要的表劳秋,將JOB和觸發(fā)器寫(xiě)入數(shù)據(jù)庫(kù),并將每個(gè)運(yùn)行中的應(yīng)用服務(wù)器編個(gè)實(shí)例名同步到對(duì)應(yīng)需要執(zhí)行的數(shù)據(jù)中胖齐,實(shí)時(shí)讀取更新庫(kù)表信息玻淑,達(dá)到控制JOB目的。持久化的JOB需要jobDataMap數(shù)據(jù)呀伙,通常把要執(zhí)行的類和方法放到Map中补履,新增一個(gè)Job調(diào)度類來(lái)進(jìn)行調(diào)度,執(zhí)行Job時(shí)取Map數(shù)據(jù)進(jìn)行實(shí)力化剿另。例如新增DetailQuartzJobBean 類進(jìn)行調(diào)度箫锤,執(zhí)行類和執(zhí)行方法配置在Map中。
調(diào)度類:DetailQuartzJobBean雨女,EasyApplicationContextUtils指spring的實(shí)例化類谚攒,根據(jù)自己項(xiàng)目情況進(jìn)行引用》斩椋可修改為 ApplicationContext ctx;馏臭,使用ctx.getBean(beanName)獲取類。
import com.ztesoft.resmaster.util.EasyApplicationContextUtils;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.lang.reflect.Method;
public class DetailQuartzJobBean extends QuartzJobBean {
protected Logger logger = LoggerFactory.getLogger(this.getClass());
private String targetObject;
private String targetMethod;
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
try {
if(targetObject==null){
targetObject=context.getJobDetail().getJobDataMap().getString("targetObject");
targetMethod=context.getJobDetail().getJobDataMap().getString("targetMethod");
}
logger.info("execute [" + targetObject + "] at once>>>>>>");
Object otargetObject = EasyApplicationContextUtils.getBeanByName(targetObject);
Method m = null;
try {
m = otargetObject.getClass().getMethod(targetMethod, new Class[]{});
m.invoke(otargetObject, new Object[]{});
} catch (SecurityException e) {
e.printStackTrace();
logger.error(e.getMessage());
} catch (NoSuchMethodException e1) { e1.printStackTrace();
logger.error(e1.getMessage());
}
} catch (Exception e) {
logger.error(e.getMessage());
}
}
public void setTargetObject(String targetObject) {
this.targetObject = targetObject;
}
public void setTargetMethod(String targetMethod) {
this.targetMethod = targetMethod;
}
}
配置信息,jobClass配置調(diào)度類讼稚,需要運(yùn)行的Job配置到j(luò)obDataAsMap中括儒。需要注意的是name這個(gè)屬性在項(xiàng)目中的所有Job中不能重復(fù)。
<bean id="saveOrderToDatabaseJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass">
<value>com.ztesoft.resmaster.module.resservice.quartz.DetailQuartzJobBean</value>
</property>
<property name="name" value="Custom-Detail-Quartz-Job-Bean_saveOrderToDatabaseJob"/>
<property name="jobDataAsMap">
<map>
<entry key="targetObject" value="qinghOrderGeneratedJob"/>
<entry key="targetMethod" value="generateOrderInfo"/>
<entry key="concurrent " value="true"/>
</map>
</property>
</bean> 配置觸發(fā)器
Job內(nèi)容主要是配置Job需要執(zhí)行的類锐想,而配置觸發(fā)器是給配置的Job設(shè)置一個(gè)執(zhí)行時(shí)間和執(zhí)行周期帮寻,一個(gè)Job可以被多個(gè)觸發(fā)器關(guān)聯(lián)執(zhí)行。關(guān)鍵屬性痛倚,jobDetail和cronExpression规婆。關(guān)聯(lián)Job配置在jobDetail屬性中,執(zhí)行周期配置在cronExpression中。
cronExpression的時(shí)間采用cron時(shí)間表達(dá)式抒蚜,具體時(shí)間格式最簡(jiǎn)單說(shuō)明就是第1位是秒掘鄙,第2位是分鐘,第3位是小時(shí)嗡髓,第4位是日期操漠,斜杠(代表每)。
如:
每分鐘到第10秒的時(shí)候執(zhí)行饿这,10 * * * * ?
每小時(shí)到第15分鐘的時(shí)候執(zhí)行浊伙,0 15 * * * ?
每天到20點(diǎn)15分鐘20秒的時(shí)候執(zhí)行,20 15 20 * * ?
每5秒執(zhí)行长捧,0/5 * * * * ?
每5分鐘執(zhí)行嚣鄙,0 0/5 * * * ?
每小時(shí)執(zhí)行,0 0 1 * * ?
涉及到更多復(fù)雜公式使用時(shí)串结,百度"cron時(shí)間表達(dá)式"
-
配置觸發(fā)器管理工廠
管理工廠是觸發(fā)器和Job的總管理處哑子,控制quartz的基礎(chǔ)屬性和觸發(fā)器的啟用。在spring配置文件中配置SchedulerFactoryBean來(lái)實(shí)現(xiàn)肌割。主要屬性 triggers,triggers下list配置需要啟用的觸發(fā)器卧蜓。單獨(dú)環(huán)境
獨(dú)立的環(huán)境直接在triggers下配置觸發(fā)器列表。
<bean id="schedulerFactory" lazy-init="false" autowire="no"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="saveOrderToDatabaseJobTrigger"/>
</list>
</property>
</bean>
集群環(huán)境
集群環(huán)境相對(duì)于單獨(dú)環(huán)境配置信息更復(fù)雜把敞,需要配置集群屬性弥奸、數(shù)據(jù)源、實(shí)例名信息奋早。通常通過(guò)加載quartz.properties配置文件盛霎,將信息配置到quartz.properties文件中,當(dāng)然也可以增加quartzProperties屬性伸蚯,將quartz.properties中的內(nèi)容配置到quartzProperties節(jié)點(diǎn)下面摩渺,效果是一樣的。
管理類配置
<bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="quartzProperties">
<props>
<prop key="org.quartz.scheduler.instanceName">quartzScheduler</prop>
<prop key="org.quartz.scheduler.instanceId">AUTO</prop>
<prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
<prop key="org.quartz.threadPool.threadCount">3</prop>
<prop key="org.quartz.threadPool.threadPriority">5</prop>
<prop key="org.quartz.jobStore.misfireThreshold">60000</prop>
<prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
<prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.MSSQLDelegate </prop>
<prop key="org.quartz.jobStore.selectWithLockSQL">SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?</prop>
<prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
<prop key="org.quartz.jobStore.isClustered">true</prop>
<prop key="org.quartz.jobStore.clusterCheckinInterval">20000</prop>
</props>
</property>
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<property name="autoStartup" value="true" />
<property name="triggers"><list><ref bean="saveOrderToDatabaseJobTrigger"/>
</list>
</property>
</bean>
注:properties屬性中可以在百度中搜"quartz.properties詳細(xì)配置"剂邮,了解含義后根據(jù)項(xiàng)目實(shí)際情況進(jìn)行調(diào)整。
其中:
- org.quartz.jobStore.isClustered代表是否集群横侦,集群環(huán)境必須配置true挥萌,
- org.quartz.jobStore.driverDelegateClass代表數(shù)據(jù)驅(qū)動(dòng)類型,Oracle可以不用配置該屬性枉侧,千萬(wàn)不要配置錯(cuò)誤引瀑,因?yàn)閿?shù)據(jù)庫(kù)結(jié)構(gòu)的差異,在配置錯(cuò)誤后榨馁,會(huì)導(dǎo)致Map等相關(guān)Job數(shù)據(jù)取數(shù)取不到而實(shí)例化對(duì)象為空憨栽,調(diào)度不到實(shí)際Job。
集群持久化后的JOB可以在三個(gè)表中檢查JOB配置和運(yùn)行情況,QRTZ_JOB_DETAILS屑柔、QRTZ_TRIGGERS屡萤、QRTZ_CRON_TRIGGERS。
<small>堅(jiān)持積累掸宛,堅(jiān)持學(xué)習(xí)死陆。</small>