最近集成用到了Quartz
需求
1.能够在接口平台实现任务调度
2.能够通过命令在接口平台添加修改任务
3.能够查看目前的任务
Quartz 和流程的关系
可在Quartz 配置触发流程的动作
在 quartz.properties 中有两个重要的属性正是满足你的需求的,如下配置用 JobInitializtionPlugin 插件的片断:
..............................
#============================================================================
# Configure Plugins
#============================================================================
org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
org.quartz.plugin.jobInitializer.fileName = quartz_jobs.xml
org.quartz.plugin.jobInitializer.failOnFileNotFound = true
org.quartz.plugin.jobInitializer.scanInterval = 5
org.quartz.plugin.jobInitializer.overWriteExistingJobs = true
最后面那两个属性,scanInterval 设置重复扫描 quartz_job.xml 文件(默认的job配置文件名)的间隔,单位为秒(默认为0,表示不自动加载),发现配置有新的 jobDetail 则加载到调度器中执行,如 overWriteExistingJobs 配置为 false(默认为 false),则碰到新的 quartz_job.xml 文件中有与现有调度器中同名的 jobDetail 则不覆盖,这就会出现,只改了job 的 cron 表达式而不能重新生效的情况;把 overWriteExistingJobs 设置为 true,就可以避免出现这种情况,可随时修改 job.xml 动态调整执行计划。
写一个通用的执行命令的类
类的参数为命令
配置quartz_jobs.xml文件
某个job的内容:
<job>
<job-detail>
<name>RunQuartzJob</name>
<group>DEFAULT</group>
<description>RunQuartzJob</description>
<job-class>RunQuartzJob</job-class>
<job-data-map allows-transient-data="true">
<entry>
<key>commandstring</key>
<value>命令名和参数(之间使用 号分开)</value>
</entry>
</job-data-map>
</job-detail>
<trigger>
<cron>
<name>RunQuartzJob</name>
<group>DEFAULT</group>
<job-name>RunQuartzJob</job-name>
<job-group>DEFALUT</job-group>
<cron-expression>0/3 * * * * ?</cron-expression>
</cron>
</trigger>
</job>
quartz在tomcat中的配置:
1.首先将quartz.jar,以及lib目录下面core和optional两个目录中的所有jar全都放入项目WEB-INF\lib目录下
这个 Web 应用的目录结构像其他任何 Web 应用是一样的。你必须添加以下文件至其中:
·web.xml (放置到 WEB-INF 下)
·quartz.properties (放置在 WEB-INF/classes 下)
·quartz_jobs.xml (放置在 WEB-INF/classes 下)
·Quartz 二进制包 (放置在 WEB-INF/lib 下)
·所需第三方包 (放置在 WEB-INF/lib 下)
2.在web.xml中增加如下内容
<servlet>
<servlet-name>
QuartzInitializer
</servlet-name>
<display-name>
Quartz Initializer Servlet
</display-name>
<servlet-class>
org.quartz.ee.servlet.QuartzInitializerServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>config-file</param-name>
<param-value>/quartz.properties</param-value>
</init-param>
<init-param>
<param-name>shutdown-on-unload</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
3.
编写quartz.properties
如果启动项目的时候,Quartz没有在工程中找到该文件,就会从自己的jar包下面读取其默认的properties文件,其内容如下:
org.quartz.scheduler.instanceName = TestScheduler
org.quartz.scheduler.instanceId = one
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 2
org.quartz.threadPool.threadPriority = 4
org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingTriggerHistoryPlugin
org.quartz.plugin.triggHistory.triggerFiredMessage = Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}
org.quartz.plugin.triggHistory.triggerCompleteMessage = Trigger {1}.{0} completed firing job {6}.{5} at {4, date, HH:mm:ss MM/dd/yyyy} with resulting trigger instruction code: {9}
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
org.quartz.plugin.jobInitializer.fileName = quartz_job.xml
org.quartz.plugin.jobInitializer.overWriteExistingJobs = false
org.quartz.plugin.jobInitializer.failOnFileNotFound = true
org.quartz.plugin.shutdownhook.class = org.quartz.plugins.management.ShutdownHookPlugin
org.quartz.plugin.shutdownhook.cleanShutdown = true
上面的
org.quartz.plugin.jobInitializer.fileName = quartz_job.xml
是用来配置定义job文件的名称。
org.quartz.plugin.jobInitializer.scanInterval = 5
org.quartz.plugin.jobInitializer.overWriteExistingJobs = true
是用来刷新配置文件的
将JobDetail的concurrent属性配置为false。不允许任务并发执行。 这样可以顺序执行任务
4.目前先手工编写和修改quartz_job.xml
5.如何实现任务的顺序执行
Job接口:自己写的“定时程序”实现此接口的void execute(JobExecutionContext arg0)方法,
Job还有一类为有状态的StatefulJob接口,如果我们需要在上一个作业执行完后,根据其执行
结果再进行下次作业的执行,则需要实现此接口。
6.Quartz的日期设置
Quartz Cron Expression
原文解释:
Field Name Mandatory? Allowed Values Allowed Special Characters
Seconds YES 0-59 , - * /
Minutes YES 0-59 , - * /
Hours YES 0-23 , - * /
Day of month YES 1-31 , - * ? / L W C
Month YES 1-12 or JAN-DEC , - * /
Day of week YES 1-7 or SUN-SAT , - * ? / L C #
Year NO empty, 1970-2099 , - * /
项目实例:
second minute hours dayOfMonth month dayOfWeek year
每月 0 0 6 ? * 6#3 ?
每周 59 59 18 ? * 1 ?
自定义 28 47 9 30 7 ? 2006
每月:每个月的第三个星期五的上午6:00:00 触发
每周:每周的星期日的下午18:59:59 触发
自定义:2006年7月30日上午9:47:28 触发
所有星号对应的段位置,都可以出现后面的符号(, - * /)
(? / L C)这些符号可以出现在"一月哪天"和"星期"段位置
(w)只能出现在"一月哪天"段位置
(#)只能出现在"星期"段位置
解释符号代表的意思:
* 代表任意合法的字段
0 * 17 * * ? :表示在每天的5 PM 到 5:59之间的每一分钟启动scheduler
? 表示没值被指定
如果同时指定"一月哪天"和"星期",可能两者对应不起来
0 0,15,30,45 * * * ? :表示每刻钟启动scheduler
所以推荐用法是其中一个指定值,另一个用?指定
/ 表示时间的增量
0 0/15 * * * ? :表示每刻钟启动scheduler
- 表示值的范围
0 45 3-8 ? * *
L 如果用在"一月哪天"段上,表示一个月的最后一天;如果用在"星期"段上。表示一个星期的最后一天(星期六)
0 0 8 L * ? :表示每个月最后一天的8点启动scheduler
W 表示最靠近给定时间的一天,(必须是星期一到星期五)
7.如何解决由于job.xml修改造成tomcat reload的问题
先将job.xml拿到web目录下,就放到config/job.xml吧.然后修改quartz.properties文件,将文件指向修改成绝对路径:
org.quartz.plugin.jobInitializer.fileName = D:/tomcat/webapps/report/config/job.xml
这样解决了所有问题,仍然可对任务明细进行操作,并且通过quartz.properties中的配置让Quartz自己发现这种变更.
而且,job.xml无论如何变更,tomcat都不会reload,因为它已经不在classes目录下了
8.quartz执行windows的bat文件
实际上是java执行bat文件的问题
如这是一个执行bat文件的例子
import java.io.*;
import java.util.*;
public class TestExec ...{
public void runbat(int timeFortmat) ...{
String cmd = "cmd /c start D:/ScheduleRun/data/"+timeFortmat+".bat";
try ...{
Process ps = Runtime.getRuntime().exec(cmd);
System.out.println(ps.getInputStream());
} catch(IOException ioe) ...{
ioe.printStackTrace();
}
}
public static void main(String[] args)...{
TestExec test1 = new TestExec ();
test1.runbat(1340);
}
}
9.Java调用bat文件后的窗口关闭问题
用类似以下的方法调用了windows bat文件
String commandstr = "cmd /c start " + path;
Process p=Runtime.getRuntime().exec(commandstr);
关键是cmd /c start 目标文件绝对路径
然后有黑色的console窗口弹出执行。
目标文件是一个启动某个java的类
形如 java -classpath=*** yyy.java
第一步到此成功,但是此文件启动的java程序在System.exit以后,黑色console窗口依然存在
请问有没有办法去掉它?
把java换成javaw试试,eclipse就是启动javaw的。