实现任务的自动调度:
系统中常常有些需要自动执行的任务,这些任务可能每隔一段时间就要执行,也可能需要在指定时间点自动执行,这些任务的自动执行必须使用任务的自动调度。
一、使用Quartz
1、下载和安装Quartz请按下步骤:
登陆:http://www.quartz-scheduler.org/站点下载Quartz的最新版本。
docs:存在Quartz的相关文档,包括API文档
examples:存放Quartz的示例程序
javadoc:存放Quartz的API文档
lib:存放Quartz的jar包
src:存放Quartz的源文件
2、将Quartz.2.2.1.jar文件添加到WEB-INF/lib路径下
3、提供一个quartz.properties配置文件,通过配置文件,可以修改框架运行时的环境。将quartz.properties文件放在类路径下。ClassLoader会自动加载并启动其中的各种属性。
quartz.properties范例如下:
//配置主调度器属性
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
//配置线程池、线程池实现类
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 15
//配置线程池里线程的优先级
org.quartz.threadPool.threadPriority = 5
//配置作业存储
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
Quartz提供两种作业存储方式:
1)、RAMJobStore,它利用内存来持久化调度程序信息,由于调度信息存储在JVM内存里,程 序终止,所有的调度信息就会丢失
2)、JDBC作业存储。需要JDBC驱动程序和后台数据库保存调度信息,有需要调度的程序维护 调度信息的用户来设计
大部分时候,RAMJobStore存储方式就足够了。
4、Quartz里的作业
Quartz里的作业需要实现org.quartz.job接口,该job接口包含一个方法execute(),execute()方法体是被调度的作业。
一旦实现了job接口和execute()方法,当Quartz调度改作业时,该execute()就会自动执行。
以下是该实例的作业:
程序清单:codes\10\QuartzQs\src\lee\TestJob.java
public class TestJob implements Job{
//判断作业是否执行的旗标
private boolean isRunning =false;
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDataMap jobDataMap = context.getMergedJobDataMap()
String getFileToRemoteFTPHost
= jobDataMap.getString("GetFileToRemoteFTPHost");
if(! isRunning ){
System.out.println(new Date(0 + " 作业被调度“);
for(int i=0;i<100;i++){
System.out.println("作业完成” + (i+1));
try{
Thread.sleep(100);
}catch(InterruptedException ex){
ex.printStackTrace();
}
}
System.out.println(new Date() +"作业调度结束);
}else {
System.out.println(new Date() +"任务退出“);
}
}
}
5、Quartz调度器
调度器用于将任务与触发器关联起来,一个任务可关联多个触发器,一个触发器也可用于控 制多个任务。
以下是一个将多个任务与触发器关联的例子:
1)、添加配置文件:ItxTransportParameters.xml
ItxTransportParameters.xml配置文件如下:
<?xml version="1.0" encoding="GBK"?>
<ItxTransportParameters>
//如果有多个作业可以添加读个job标签
<job>
<job-detail>
<name>TestJob</name>
<group>FTP</group>
<job-class>src.lee.TestJob</job-class>
//作业需要的属性值
<job-data-map allows-transient-data="true">
<entry>
<key>GetFileFromPath</key>
<value>/home/bea</value>
</entry>
</job-data-map>
</job-detail>
//任务调度的时间
<trigger>
<cron>
<name>TestJobJobTrigger</name>
<group>FTP</group>
<job-name>TestJob</job-name>
<job-group>FTP</job-group>
<cronExpression>0 0/3 0-23 * * ?</cronExpression>
</cron>
</trigger>
</job>
</ItxTransportParameters>
2)、任务调度
public class ItxTransportListener {
private List<Scheduler> schedulers = new ArrayList<Scheduler>();
String configFileName = "ItxTransportParameters.xml";
public static void main(String[] args) {
ItxTransportListener server= new ItxTransportListener();
try {
server.startScheduler();
} catch (Exception ex) {
ex.printStackTrace();
server.stop();
}
//执行调度
public void startScheduler() throws SchedulerException {
//解析itxparameter.xml中jobDetil节点,创建JobDetail
Element testConfig
= XMLUtils.parseElement(cl.getResourceAsStream(configFileName));
Element jobElem = (Element) tcpConfigs.item(i);
Element jobDetailElem
= (Element) jobElem.getElementsByTagName("job- detail").item(0);
String name
= jobDetailElem.getElementsByTagName("name")
.item(0).getFirstChild().getNodeValue();
String group
= jobDetailElem.getElementsByTagName("group")
.item(0).getFirstChild().getNodeValue();
String jobClass
= jobDetailElem.getElementsByTagName("job-class")
.item(0).getFirstChild().getNodeValue();
//使用工厂创建调度器实例
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//创建JobDetail实例
JobDetail jobDetail = new JobDetail(name, group, Class.forName(jobClass));
//将itxtransparameter.xml中,定时器的key、value保存到jobDetail中
for(int j = 0; j < jobDetailElem.getElementsByTagName("entry").getLength(); j++){
Element jobDataElem
= (Element) jobDetailElem.getElementsByTagName("entry").item(j);
String key
= jobDataElem.getElementsByTagName("key")
.item(0).getFirstChild().getNodeValue();
NodeList list = jobDataElem.getElementsByTagName("value");
if(list != null){
if(list.getLength() == 1 && list.item(0).getFirstChild() != null){
String value = list.item(0).getFirstChild().getNodeValue();
jobDetail.getJobDataMap().put(key, value);
} else if(list.getLength() > 1){
List<String> values = new ArrayList<String>();
for(int index = 0; index < list.getLength(); index ++){
String value = list.item(index).getFirstChild().getNodeValue();
if(StringUtils.isNotBlank(value))
values.add(value);
}
jobDetail.getJobDataMap().put(key, values);
}
}
}
//解析配置文件中Trigger节点,创建调度器Trigger
Element cronTriggerElem
= (Element) triggerElem.getElementsByTagName("cron").item(0);
name
= cronTriggerElem.getElementsByTagName("name").item(0)
.getFirstChild().getNodeValue();
group = cronTriggerElem.getElementsByTagName("group")
.item(0).getFirstChild().getNodeValue();
String cronExpression = cronTriggerElem
.getElementsByTagName("cronExpression")
.item(0).getFirstChild().getNodeValue();
//创建Trigger对象,该对象是调度器
Trigger trigger = new CronTrigger(name, group, cronExpression);
//将作业与调度关联起来
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
schedulers.add(scheduler);
}
public void stop() throws SchedulerException {
for (Scheduler scheduler : schedulers)
scheduler.shutdown();
}
}
}
二、spring Quatrz
1、作业,继承QuartzJobBean 类,覆盖其executeInternal方法
程序清单:codes\10\HRSystem\Web-INF\src\org\crazyit\hrsystem\schedule\PunchJob.java
public class PunchJob extends QuartzJobBean{
private boolean isRunning =false;
private EmpManager empMgr;
public void setEmpMgr(EmpManager empMgr){
this.empMgr = empMgr;
}
public void executeInternal(JobExecutionContext ctx)
throws JobExecutionException{
if(!isRunning){
System.out.println("开始调度自动打卡”);
isRunning = true;
//调用业务逻辑方法
empMgr.autoPunch();
isRunning = false;
}
}
2、在spring配置文件中添加如下配置
<bean id="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="configLocation" value="classpath:quartz.properties"/>
<property name="triggers">
<list>
<ref bean="PunchJobTrigger" />
</list>
</property>
</bean>
<bean id="PunchJobLauncherDetail" class=
"org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="org.crazyit.hrsystem.schedule.PunchJob.java" />
<property name="group" value="quartz-reconcile" />
<property name="jobDataAsMap">
<map>
<entry key="jobName" value="dbsAutoPayRequestReconcileJob" />
</map>
</property>
</bean>
<bean id="PunchJobTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="PunchJobLauncherDetail" />
<property name="cronExpression" value="0 0 5 * * ?" />
</bean>