喜欢从业的专注,七分学习的态度。
概述
Java项目定时任务(JOB)首选quartz,一般我们选择集成到Spring中变成Spring+Quartz。抛开API和复杂的部署逻辑,简述简单配置经验。 根据实际部署情况需要区分:单独环境,集群环境。
Job单独环境:只有一台机器运行JOB,不存在任务冲突和抢任务问题。
集群环境:存在多个机器多个应用服务器,每个应用都会运行JOB,产生任务、事物抢占等一系列资源冲突问题,在集群环境下需要保证多个应用服务器中同一时间只有一个应用服务运行JOB。
原理简述
-
配置步骤
要配置一个能执行任务类的JOB分为三部分,配置JOB内容、配置执行JOB的触发器、配置触发器管理工厂。
-
配置JOB内容
配置一个bean,用来指定Job需要运行的类和方法。具体在Spring的xml中配置,区分单独环境和集群环境。单独环境
配置 一个job执行 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>集群环境
集群环境需要将JOB持久化,才能实现集群中唯一执行。就是将JOB信息写入到数据库表中,Quartz利用自带创建表脚本自动创建对应需要的表,将JOB和触发器写入数据库,并将每个运行中的应用服务器编个实例名同步到对应需要执行的数据中,实时读取更新库表信息,达到控制JOB目的。持久化的JOB需要jobDataMap数据,通常把要执行的类和方法放到Map中,新增一个Job调度类来进行调度,执行Job时取Map数据进行实力化。例如新增DetailQuartzJobBean 类进行调度,执行类和执行方法配置在Map中。
调度类:DetailQuartzJobBean,EasyApplicationContextUtils指spring的实例化类,根据自己项目情况进行引用。可修改为 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配置调度类,需要运行的Job配置到jobDataAsMap中。需要注意的是name这个属性在项目中的所有Job中不能重复。
<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> -
配置触发器
Job内容主要是配置Job需要执行的类,而配置触发器是给配置的Job设置一个执行时间和执行周期,一个Job可以被多个触发器关联执行。关键属性,jobDetail和cronExpression。关联Job配置在jobDetail属性中,执行周期配置在cronExpression中。
cron时间表达式cronExpression的时间采用cron时间表达式,具体时间格式最简单说明就是第1位是秒,第2位是分钟,第3位是小时,第4位是日期,斜杠(代表每)。
如:
每分钟到第10秒的时候执行,10 * * * * ?
每小时到第15分钟的时候执行,0 15 * * * ?
每天到20点15分钟20秒的时候执行,20 15 20 * * ?
每5秒执行,0/5 * * * * ?
每5分钟执行,0 0/5 * * * ?
每小时执行,0 0 1 * * ?
涉及到更多复杂公式使用时,百度"cron时间表达式"
-
配置触发器管理工厂
管理工厂是触发器和Job的总管理处,控制quartz的基础属性和触发器的启用。在spring配置文件中配置SchedulerFactoryBean来实现。主要属性 triggers,triggers下list配置需要启用的触发器。单独环境
独立的环境直接在triggers下配置触发器列表。
<bean id="schedulerFactory" lazy-init="false" autowire="no"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="saveOrderToDatabaseJobTrigger"/>
</list>
</property>
</bean>
集群环境
集群环境相对于单独环境配置信息更复杂,需要配置集群属性、数据源、实例名信息。通常通过加载quartz.properties配置文件,将信息配置到quartz.properties文件中,当然也可以增加quartzProperties属性,将quartz.properties中的内容配置到quartzProperties节点下面,效果是一样的。
管理类配置
<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详细配置",了解含义后根据项目实际情况进行调整。
其中:
- org.quartz.jobStore.isClustered代表是否集群,集群环境必须配置true,
- org.quartz.jobStore.driverDelegateClass代表数据驱动类型,Oracle可以不用配置该属性,千万不要配置错误,因为数据库结构的差异,在配置错误后,会导致Map等相关Job数据取数取不到而实例化对象为空,调度不到实际Job。
集群持久化后的JOB可以在三个表中检查JOB配置和运行情况,QRTZ_JOB_DETAILS、QRTZ_TRIGGERS、QRTZ_CRON_TRIGGERS。
<small>坚持积累,坚持学习。</small>
网友评论