四. 创建一个工作流 Job
最后,我们需要介绍启动工作流的 Quartz Job 。当 Scheduler 调用了它,Quartz Job 就查找工作流的名字,并启动、运行相应的工作流。如果没有在 JobDataMap 中配置工作流的名字,Job 就会直接退出。
代码 14.13 显示了 WorkflowJob.
代码 14.13. Quartz WorkflowJob 设计为调用一个 OSWorkflowJob
| 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 | public class WorkflowJob implements Job {      static Log logger = LogFactory.getLog(WorkflowJob.class);      /**       * Called by the scheduler to execute a workflow       */      public void execute(JobExecutionContext context)                throws JobExecutionException {           JobDataMap jobDataMap = context.getJobDataMap();           String wfName = jobDataMap.getString("WORKFLOW_NAME");           if (wfName != null && wfName.length() > 0) {                try {                     executeWorkflow(wfName, jobDataMap);                } catch (Exception ex) {                     logger.error(ex);                          throw new                               JobExecutionException(ex.getMessage());                }           } else {                logger.error("No Workflow name in JobDataMap");           }      }      protected void executeWorkflow(String workflowName,           JobDataMap jobDataMap) throws WorkflowException {           // Create the inputs for the workflow from JobDataMap           Map workflowInputs = new HashMap();           Iterator iter = jobDataMap.keySet().iterator();           while (iter.hasNext()) {                String key = (String) iter.next();                Object obj = jobDataMap.get(key);                workflowInputs.put(key, obj);           }           // Create and execute the workflow           Workflow workflow = new BasicWorkflow("someuser");           workflow.setConfiguration(new DefaultConfiguration());           long workflowId = workflow.initialize(workflowName, 1, workflowInputs);           workflow.doAction(workflowId, 1, workflowInputs);       } } | 
这个工作流实际是在代码 14.13 的 executeWorkflow() 方法中启动的。一个新的工作流实例被创建了。它通过从 JobDataMap 中读取到的工作流名字来初始化的。工作流实例的 initialize() 和 doAction() 方法用了一个 java.util.Map 作为第三个参数。Map 中的值会通过 transientVars 参数传递到工作流的每一个函数中。如果你回头看看代码 14.11,你会看到 SCAN_DIR 是如何从 transientVars 抽取出来的。这个数据最初是在 JobDataMap 的。
本例中,我们从 Quartz Job 中获得 JobDataMap 并传值到工作流中。这是集成这两个框架的其中一种方式,简单也很直截。
最后,代码 14.14 显示了 Scheduler 的代码,它用于部署 WorkflowJob 并把工作流名称和 SCAN_DIR 存入到 JobDataMap 中。
代码 14.14. WorkflowJob 以正常方式部署,但必须存工作流名称到 JobDataMap 中
| 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 | public class WorkflowScheduler {      static Log logger = LogFactory.getLog(WorkflowScheduler.class);      public static void main(String[] args) {           try {                // Create and start the Scheduler                Scheduler scheduler =                     StdSchedulerFactory.getDefaultScheduler();                scheduler.start();                JobDetail jobDetail =                     new JobDetail("WorkflowJob", null,                          WorkflowJob.class);                // Store the scan directory and workflow name                JobDataMap dataMap = jobDetail.getJobDataMap();                dataMap.put("SCAN_DIR", "c:\\quartz-book\\input");                dataMap.put("WORKFLOW_NAME", "data-import");                // Create a simple trigger                Trigger trigger =                     TriggerUtils.makeSecondlyTrigger(30000, -1);                trigger.setName("WorkflowTrigger");                trigger.setStartTime(new Date());                // schedule the job                scheduler.scheduleJob(jobDetail, trigger);           } catch (SchedulerException ex) {                logger.error(ex);           }      } } | 
你看到代码 14.14 时不应感到惊讶。唯一要注意的事情是我们存储了工作流名称到 JobDataMap 中。和本章前面的 Job 串联例子一样,假如你想使用 JobInitializationPlugin,你可以简单的在文件中指定工作流的名称。
五. 小结
我们从本章中学到了什么?首先,Job 串联可由 Quartz 框架实现。你可用所介绍的两种方法,只是不借助于监听器实现的方式或许会让你有些头疼。我希望你带走的另一课是 Job 串联并非工作流。它也许看起来像工作流,你可能还对此存有疑虑,只要回到前面从头至尾构建一个自己的例子就能清楚了。一定要读一读 OSWorkflow 的文档并找出我们未提及的特性。你就能明白工作流比 Job 串联丰富多了。
最后,你应该了解到了同 Quartz 一同使用 OSWorkflow 实际是颇为简单的。所有要用到的就是几个二进制包,几个配置文件和一些工作流函数。把它们同工作流定义文件打包到一块,你就大功告成了。很快,你就将构建出一个可重用的函数库和一连串工作流来运行你的业务。不久,你就会有一个为之自豪的精致小巧的应用程序。
本文链接 https://yanbin.blog/quartz-job-scheduling-framework-14-4/, 来自 隔叶黄莺 Yanbin Blog
[版权声明]  本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
加油!!!
请教一个问题,JobDetail初始化时为什么是传Class而不是传实例化而的对象?传Class的问题在于Job类无法使用有参数的构造方法初始化。把初始化任务放在Job.execute()每次循环都执行效率有问题吧。比如
class MyJob implements Job {
private String config;
MyJob(String config) {
this.config = config;
}
}
class Example {
public static void main(String[] arg) {
......
JobDetail job = new JobDetail("job1", null, MyJob.class);
......
}
}
这样MyJob.config就没办法用构造函数设置了呀,有什么解决方法吗?
相信我在QQ里给你的解答你已经很清楚了,因为问及,不妨也在这里回答一下。因为 Quartz 设计为线程安全的,也就是每次执行 Job 都需要创建一个新的 Job 实例,所以你所希望的初始工作放在 Job 的构造方法或是 execute() 方法中效率都会是一样的,因此该考虑其他方法来进行你要的初始化操作。