二. 创建 Quartz 插件
创建一个新的插件很简单。你所有要做的就是创建一个 Java 类(或重用一个现有的类),让它实现 org.quartz.spi.SchedulerPlugin 接口。Scheduler 将会在启动期间创建这个插件的实例。这个插必须有一个无参的构造方法,很显然它不能是抽象的。
·JobInitializationPlugin
Quartz 框架有一个用来从 XML 文件中加载 Job 和 Trigger 信息的插件。这个插件就是 org.quartz.plugins.xml.JobInitializationPlugin,并且它在前面第三章 "Hello, Quartz" 中简略的讨论过。当你使用这个插件的时候,Quartz 框架就会搜寻一个叫做 quartz_jobs.xml 的文件并试图从中加载 Job 和 Trigger 信息。
改变 JobInitializtionPlugin 加载的 XML 文件 插件允许你改变它要查找来加载 Job 和 Trigger 信息的文件的名字。你可以通过在 quartz.properties 文件中设置一个别的文件名。我们会在本章后续中讲到更多的关于设置插件参数的内容。 |
如第三章所解释的,这个插件在你的应用需求不涉及到从数据库中加载 Job 信息时是很方便的。它在开发和测试期间也是很有用的,因为你可以快速的配置哪些 Job 和 Trigger 要被触发。就是说,无可争辩的,修改一个 XML 总比一系列的数据库表要简单。
对于从一个 XML 文件中加载 Job 和 Trigger 信息做法的一个很好的延展就是可以有一个目录来存储 Job XML 文件,然后过使用一个插件,Scheduler 就会加载任何存在的 Job 文件了。这允许你在 Scheduler 启动时简单从指定的目录中添加或移除 Job 文件来方便的增加或删除 Job。在本章剩下的部分,我们向你展示如何构建这个插件。
·创建 JobLoaderPlugin
我们把这个新插件命名为 JobLoaderPlugin。代码 8.2 中显示了这个 JobLoaderPlugin 类。
代码 8.2. 从一个目录中加载多个 Job 文件的 Quartz SchedulerPlugin
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
package org.cavaness.quartzbook.chapter8; import java.io.File; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.quartz.Scheduler; import org.quartz.SchedulerConfigException; import org.quartz.SchedulerException; import org.quartz.spi.SchedulerPlugin; import org.quartz.xml.JobSchedulingDataProcessor; public class JobLoaderPlugin implements SchedulerPlugin { private static Log logger = LogFactory.getLog(JobLoaderPlugin.class); // The directory to load jobs from private String jobsDirectory; // An array of File objects private File[] jobFiles = null; private String pluginName; private Scheduler scheduler; private boolean validateXML = true; private boolean validateSchema = true; public JobLoaderPlugin() { } public File[] getJobFiles() { return jobFiles; } public void setJobFiles(File[] jobFiles) { this.jobFiles = jobFiles; } public boolean isValidateSchema() { return validateSchema; } public void setValidateSchema(boolean validatingSchema) { this.validateSchema = validatingSchema; } public void initialize(String name, final Scheduler scheduler) throws SchedulerException { this.pluginName = name; this.scheduler = scheduler; logger.debug("Registering Plugin " + pluginName); // Load the job definitions from the specified directory loadJobs(); } private void loadJobs() throws SchedulerException { File dir = null; // Check directory if (getJobsDirectory() == null || !(dir = new File(getJobsDirectory())).exists()) { throw new SchedulerConfigException( "The jobs directory was missing " + jobsDirectory); } logger.info("Loading jobs from " + dir.getName()); // Only XML files, filtering out any directories this.jobFiles = dir.listFiles(new XMLFileOnlyFilter()); } public void start() { processJobs(); } public void shutdown() { // nothing to clean up } public void processJobs() { // There should be at least one job if (getJobFiles() == null || getJobFiles().length == 0) { return; } JobSchedulingDataProcessor processor = new JobSchedulingDataProcessor( true, isValidateXML(), isValidateSchema()); int size = getJobFiles().length; for (int i = 0; i < size; i++) { File jobFile = getJobFiles()[i]; String fileName = jobFile.getAbsolutePath(); logger.debug("Loading job file: " + fileName); try { processor.processFileAndScheduleJobs( fileName, scheduler, true); } catch (Exception ex) { logger.error("Error loading jobs: " + fileName); logger.error(ex); } } } public String getJobsDirectory() { return jobsDirectory; } public void setJobsDirectory(String jobsDirectory) { this.jobsDirectory = jobsDirectory; } public String getPluginName() { return pluginName; } public void setPluginName(String pluginName) { this.pluginName = pluginName; } public boolean isValidateXML() { return validateXML; } public void setValidateXML(boolean validateXML) { this.validateXML = validateXML; } } |
代码 8.2 中 JobLoaderPlugin 的实际工作仅是由两个方法:initialize() 和 start() 来完成的。它们是 SchedulerPlugin 接口所必须的。其他的方法只是 setXXX 和 getXXX 方法是用于实现 JavaBean 规范的,因为声明了私有属性。
·JobLoaderPlugin initialize() 方法
正如你看到的,由 Scheduler 调用的 initialize() 方法会调用 loadJobs() 方法。loadJobs() 方法使用从 quartz.properties 文件传入的 jobsDirectory 所指示的目录中获取所有的 XML 文件。这个插件还不会试图部署 Job,因为在插件的 initialize() 方法被调用的时候 Scheduler 还没有完全初始化好。JobLoaderPlugin 只简单的持有一个 File 对象的数组,直等 start() 方法被调用。我们还持有了一个 Scheduler 实例,以便我们在 start() 方法在调用时能访问它。
·JobLoaderPlugin start() 方法
当 Scheduler 调用 JobLoaderPlugin 的 start() 方法时,start() 方法就调用 processJobs()。processJobs() 方法遍历那个 Job 文件的数组并把每个都加载到 Scheduler 实例中。
对 Job 文件的处理是通过一个 org.quartz.xml.JobSchedulingDataProcessor 实例来完成的。调用 processFileAndScheduleJobs() 方法并传入文件名,Scheduler 实例和一个布尔值告诉它是否覆盖已有的 Job。
当 processJobs() 方法完成后,这个指定 jobsDirectory 下的所有 Job 文件就已经被加载并被部署了。
本文链接 https://yanbin.blog/quartz-job-scheduling-framework-8-2/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
到了 Quartz 1.8.4 的版本请使用 org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin 和 org.quartz.xml.XMLSchedulingDataProcessor 这两个类来加载 Job 定义 XML 文件的。请了解下这两个类的功能。
隔叶黄莺 :你好.
我使用的是 quartz-1.8.4
在看着这个地方的时候,我发现在1.84的版本中是没有
org.quartz.xml.JobSchedulingDataProcessor
这个类的.
请问 JobLoaderPlugin 中我要如何解决错误.
随便问下那个 JobSchedulingDataProcessor 是干嘛的?
联系方式:longjianmin@sina.com
补上 XMLFileOnlyFilter 的实现代码,这个过滤器可以随意实现 FileFilter 和 FilenameFilter 中的一个,它们都可以用在本例中,如下:
1) 实现 FileFilter:
import java.io.FileFilter; /**
* XML 文件过滤器
* @author Unmi
*/
public class XMLFileOnlyFilter implements FileFilter {
public boolean accept(File pathname) {
//是文件并且扩展名为 xml 时则返回 true
if(pathname.isFile()
&& pathname.getName().toLowerCase().endsWith(".xml")){
return true;
}
return false;
}
}
2) 实现 FilenameFilter:
import java.io.FilenameFilter; /**
* XML 文件过滤器
* @author Unmi
*/
class XMLFileOnlyFilter implements FilenameFilter{
public boolean accept(File dir, String name) {
//是文件并且扩展名为 xml 时则返回 true
if(new File(dir,name).isFile() &&
name.toLowerCase().endsWith(".xml")){
return true;
}
return false;
}
}