`
wu_quanyin
  • 浏览: 205056 次
  • 性别: Icon_minigender_1
  • 来自: 福建省
社区版块
存档分类
最新评论

任务调度---Quartz

阅读更多

一,最近在开发任务调度(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







 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics