一,最近在开发任务调度(job)这一块,在此进行总结
1,在jdk中提供了基本的Timer,TimerTask可以用作其本的任务调度操作,不过功能不够强大
2,quartz框架为我们提供了一系列的任务调度操作,基本的应用操作等都很容易理解.(JobDetail,Trigger)
二,由于公司要使quartz与公司建模端平台互相协作,产生的问题
建模端(提供xml配置与job类)----------------------中间层(定时扫描xml,根据xml语义的改变而改变)
1,可配置,在起初时使用的是1.6版本,这个版本没有提供插件配置机制,在为如何定义xml,如何让线程合理操作烦恼,看了下官方文档,原来1.8中已经提供了可配置的插件机制,非常方便,
org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin(可认真查看此插件的源码) 这个类提供了全套的服务.,
.可在定义的xml中配置想要的job,此插件还提供了对此xml隔时对此进行查询操作,对xml中配置的内容意义识别(可删除,可替换)
2,在部暑到tomcat上出现了一个问题,那就是webappClassloader缓存了任务调度的xml,也就是说建模端对xml进行更改或是添加job,并不会被读取..
.解决方案,跟踪了下源码发现插件中查找文件是使用了(classloader getResourceAsStream(String name))进行查找,
故自己重新写了个自定义的classloader,用来专门加载quartz
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
/**
* 任务调度时查询classpath下的scheduler.xml时,
* webappclassloader使用了缓存,不能及时更新
* 该文件下的job,故重写classloader
*
* @author wu_quanyin(09817)
* @version 1.0
* @date 2010-08-19 下午01:53:25
*/
public class QuartzClassLoader extends URLClassLoader {
public QuartzClassLoader(File directoryPath, ClassLoader parent) {
super(new URL[0],parent);
if(directoryPath.isDirectory()){
File[] files=directoryPath.listFiles();
for(int i=0;i<files.length;i++){
try {
this.addURL(files[i].toURI().toURL());
} catch (MalformedURLException e) {
e.printStackTrace();
}
}
}
}
/**
* quartz查找scheduler.xml时,使用些方法查找
*/
public InputStream getResourceAsStream(String name) {
URL url = getResource(name);
try {
return url != null ? url.openStream() : null;
} catch (IOException e) {
return null;
}
}
public URL getResource(String name) {
URL[] urls=this.getURLs();
for(int i=0;i<urls.length;i++){
if(urls[i].getPath().indexOf(name)!=-1){
return urls[i];
}
}
return super.getResource(name);
}
}
然后设置进(parent 为webappclassloader先查找quartzclassloader再查找parent)
/*
* CopyRright (c) 2009-2015 www.fdauto.com
*/
package com.fdauto.bws.common.scheduler;
import java.io.File;
import java.lang.reflect.Method;
import java.util.Properties;
import com.fdauto.bws.common.logger.SystemLogsHelper;
import com.fdauto.bws.service.config.BWSConfigHelper;
/**
* 任务调度
*
* @author wu_quanyin(09817)
* @version 1.0
* @date 2010-5-5 上午07:54:01
*/
public class QuartzStdScheduler {
private Properties ps;
private Object schedulerObject;
private static QuartzStdScheduler inst;
private static String jobs_full_path;
private static String quartz_classpath;
private static String scheduler_name;
private QuartzClassLoader quartzClassLoader;
static {
jobs_full_path = BWSConfigHelper.getBWSConfig().getProperties()
.getProperty("jobFiles");
quartz_classpath = jobs_full_path.substring(0, jobs_full_path
.lastIndexOf("/"));
scheduler_name = jobs_full_path.substring(jobs_full_path
.lastIndexOf("/") + 1);
}
private QuartzStdScheduler() {
initial();
schedulerObject = createScheduler();
}
/** 单例模式 */
public static QuartzStdScheduler getInstance() {
if (inst == null) {
inst = new QuartzStdScheduler();
}
return inst;
}
/** 对属性进行初始化 */
private void initial() {
// -----------------------------------------以自定义的classLoader来控制quartz的执行
quartzClassLoader = new QuartzClassLoader(new File(this.getClass()
.getClassLoader().getResource(quartz_classpath).getFile()),
this.getClass().getClassLoader());
Thread.currentThread().setContextClassLoader(quartzClassLoader);
// --------------------------------------------------------------初始化quartz的环境
ps = new Properties();
ps.setProperty(QuartzProperties.PROP_SCHED_INSTANCE_NAME,
"DefaultQuartzScheduler");
ps.setProperty(QuartzProperties.PROP_THREAD_COUNT, "10");
ps.setProperty(QuartzProperties.PROP_THREAD_POOL_CLASS,
"org.quartz.simpl.SimpleThreadPool");
ps.setProperty(QuartzProperties.PROP_JOB_STORE_CLASS,
"org.quartz.simpl.RAMJobStore");
ps.setProperty("org.quartz.plugin.triggHistory.class",
"org.quartz.plugins.history.LoggingJobHistoryPlugin");
ps.setProperty(QuartzProperties.PROP_PLUGIN_CLASS,
"org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin");
ps.setProperty(QuartzProperties.PROP_PLUGIN_SCANINTERVAL, "180");
/**
* 根据指定job文件进行创建,以逗号分隔文件,在bws.xml中配置路径
* com/fdauto/bws/common/scheduler/quartz_jobs.xml,
* com/fdauto/bws/common/scheduler/quartz_jobs2.xml
*/
ps.setProperty(QuartzProperties.PROP_PLUGIN_FILESNAME, scheduler_name);
}
/**
* 创建scheduler
*
* @return
*/
private Object createScheduler() {
try {
Object schedulerFactoryObject = quartzClassLoader.loadClass(
"org.quartz.impl.StdSchedulerFactory").getConstructor(
new Class[] { Properties.class }).newInstance(
new Object[] { ps });
Method method = schedulerFactoryObject.getClass().getMethod(
"getScheduler", new Class[] {});
Object schedulerObject = method.invoke(schedulerFactoryObject,
new Object[] {});
return schedulerObject;
} catch (Exception e) {
SystemLogsHelper.error("创建调度器失败", e.getCause());
e.printStackTrace();
}
return null;
}
/** 执行任务调度器里的方法 */
private Object invokeSchedule(String methodName, Object... objects) {
Class<?>[] clazzs = new Class[objects.length];
for (int i = 0; i < objects.length; i++) {
clazzs[i] = objects[i].getClass();
}
try {
Method method = schedulerObject.getClass().getMethod(methodName,
clazzs);
return method.invoke(schedulerObject, objects);
} catch (Exception e) {
SystemLogsHelper.error("调度器执行" + methodName + "失败", e.getCause());
e.printStackTrace();
}
return null;
}
/** 启动调度器 */
public void start() {
if (this.schedulerObject != null) {
SystemLogsHelper.info("开始启动任务调度器.......");
this.invokeSchedule("start", new Object[] {});
SystemLogsHelper.info("任务调度器启动完成!");
}
}
/** 暂停调度器 */
public void pause() {
if (this.schedulerObject != null) {
this.invokeSchedule("standby", new Object[] {});
}
}
/** 停止调度器 */
public void stop() {
if (this.schedulerObject != null) {
// 加true意思是停止之前完成正在执行的 Job,false是立即停止
this.invokeSchedule("shutdown", new Object[] {});
}
}
/** 中断job,要配合Job implements InterruptableJob 使用 */
public void interruptJob(String jobName, String groupName) {
if (this.schedulerObject != null) {
this
.invokeSchedule("interrupt", new Object[] { jobName,
groupName });
}
}
/** 删除job */
public void deleteJob(String jobName, String groupName) {
if (this.schedulerObject != null) {
this.invokeSchedule("deleteJob",
new Object[] { jobName, groupName });
}
}
}
之后可对这个类进行启动等操作,也可定时操作任务调度的xml
注:
以上只能通过反射的方式调用,由于classloader的安全机制,同样的类,父classloader装载的类 和 子classloader装载的类不能互相转换。不能够用强制转换
http://waterdh.iteye.com/blog/520399