Quartz Job Scheduling Framework[翻译]第十三章. Quartz 和 Web 应用 (第三部分)

四. QuartzInitializerServlet 可谓救命草


Quartz 框架包括一个叫做 org.quartz.ee.servlet.QuartzInitializerServlet 的 Java 类,它继承自标准的 HttpServlet。你可应用这个 servlet 于你的 Web 应用中,它将会创建一个 StdSchedulerFactory 实例并在你的程序后续中一直可用。通常的,它就是做了命令行版本的 Quartz 程序的 main() 方法所做的事性。


QuartzInitializerServlet 在 Quartz 1.5 中有所改变
在 Quartz 的 1.5 发布版中,QuartzInitializerServlet 被修改为会存储 StdSchedulerFactory 实例到 Web 应用的 ServletContext 中。这就允许你的程序在任何地方都能访问到 Scheduler 实例,只要获取到了 HttpServletRequest 或 HttpSession 对象,调用工厂的 getScheduler() 就访问到了 Scheduler 实例。

还新增了一个 start-scheduler-on-load 的 Servlet 初始化参数。这一参数指定 Scheduler 是否随 QuartzInitializerServlet 启动或是别处启动。假如未设置时默认为 True,Sheduler 将随 QuartzInitializerServlet 起来。否则,你的应用将不得不自己去获得 Scheduler 实例然后调用 start() 方法。

当容器加载 QuartzInitializerServlet,该 Servlet 的 init() 方法将被调用。这个 Servlet 读取几个初始化参数,创建 StdSchedulerFactory 类的实例,并使用指定(或默认) 的 Quartz 属性文件来初始化 Scheduler。

工厂创建之后,init() 方法就会决定 Scheduler 是否立即启动,或是让程序来决定何时启动它。代码 3.1 列出了 QuartzInitializerServlet 的 init() 方法。

代码 13.1. QuartzIniializerServlet 类的 init() 方法
 1public void init(ServletConfig cfg) throws ServletException {
 2 super.init(cfg);
 3
 4 log("Quartz Initializer Servlet loaded, initializing Scheduler...");
 5
 6 StdSchedulerFactory factory;
 7 try {
 8
 9   String configFile = cfg.getInitParameter("config-file");
10   String shutdownPref = cfg.getInitParameter("shutdown-on-unload");
11
12   if (shutdownPref != null)
13
14     performShutdown = Boolean.valueOf(shutdownPref).booleanValue();
15
16   // get Properties
17   if (configFile != null) {
18     factory = new StdSchedulerFactory(configFile);
19   } else {
20     factory = new StdSchedulerFactory();
21   }
22
23   // Should the Scheduler being started now or later
24   String startOnLoad =
25     cfg.getInitParameter("start-scheduler-on-load");
26
27   /*
28    * If the "start-scheduler-on-load" init-parameter is not specified,
29    * the
30    * scheduler will be started. This is to maintain backwards
31    * compatability.
32    */
33
34    if (startOnLoad == null ||
35     (Boolean.valueOf(startOnLoad).booleanValue())) {
36     // Start now
37     scheduler = factory.getScheduler();
38     scheduler.start();
39     log("Scheduler has been started...");
40   } else {
41     log("Scheduler has not been started. Use scheduler.start()");
42   }
43
44   log(
45    "Storing the Quartz Scheduler Factory in the servlet context at key: " +
46 QUARTZ_FACTORY_KEY);
47   cfg.getServletContext().setAttribute(QUARTZ_FACTORY_KEY, factory);
48
49 } catch (Exception e) {
50   log("Quartz Scheduler failed to initialize: " +
51e.toString());
52   throw new ServletException(e);
53 }
54}

QuartzInitializerServlet 是 Quartz JAR 文件的一部分。只要你 Web 应用的 WEB-INF/lib 中有了 quartz.jar,这个 Servlet 在你的应用中就是可用的了。

·配置 Web 部署描述文件

Java Servlet 规范规定了每个 Web 应用都必须包含一个 Web 部署描述文件。部署文件(web.xml) 中包含了以下类型的信息:

    ·初始化参数

    ·Session 配置

    ·Servlet/JSP 定义

    ·Servlet/JSP 映射

    ·MIME 类型映射

    ·欢迎文件

    ·错误页面

    ·安全性

因为 QuartzInitializerServlet 是一个 Java Servlet,它必须配置到部署描述文件中让容器来加载它。代码 13.2 描绘了怎样在 web.xml 文件中配置 QuartzInitializerServlet。

代码 13.2. QuartzInitializerServlet 需要对 web.xml 文件作相应的修改
 1<web-app>
 2<servlet>
 3 <servlet-name>QuartzInitializer</servlet-name>
 4 <display-name>Quartz Initializer Servlet</display-name>
 5
 6 <servlet-class>
 7   org.quartz.ee.servlet.QuartzInitializerServlet
 8 </servlet-class>
 9
10 <load-on-startup>1</load-on-startup>
11
12 <init-param>
13   <param-name>config-file</param-name>
14   <param-value>/some/path/my_quartz.properties</param-value>
15 </init-param>
16
17 <init-param>
18   <param-name>shutdown-on-unload</param-name>
19   <param-value>true</param-value>
20 </init-param>
21
22 <init-param>
23   <param-name>start-scheduler-on-load</param-name>
24   <param-value>true</param-value>
25 </init-param>
26
27</servlet>
28
29<! other web.xml items here >
30
31</web-app>

QuartzInitializerServlet 支持三个 Quartz 规范的初始化参数

初始化参数 config-file

config-file 参数用来指定 Quartz 属性文件的路径和文件名。StdSchedulerFactory 使用这个文件配置 Scheduler 实例。这个参数是可选的;假如未指定,就会用默认的 quartz.properties 文件。使用此参数最简单的方式(假定你想提供自己的属性文件) 是把你的属性文件放到 WEB-INF/classes 目录中,然后如下方式指定 init-param:
1<init-param>
2 <param-name>config-file</param-name>
3  <param-value>/my_quartz.properties</param-value>
4</init-param>

初始化参数 shutdown-on-unload

shutdown-on-unload 参数用于在容器卸载本 Servlet 时引起 scheduler.shutdown() 方法的调用。一个容器在关闭,或某种条件时,在一个热部署环境中重新加载时就会卸载这个 Servlet。这个参数是可选的,默认值是 true。

初始化参数 start-scheduler-on-load

start-scheduler-on-load 参数用于告诉 Servlet 调用 Scheduler 实例的 start() 方法。假如它没有启动,Scheduler 就需要由程序在晚些时候来启动,在 start() 未被调用之前是不会有 Job 运行的。这一参数是可选的,如果未指定时默认为 true。这个参数是在 1.5 发行版中加载来,不存在于早期版本中。

·访问 SchedulerFactory 和 Scheduler

自 Quartz 1.5 开始,QuartzInitializerservlet 将自动将 StdSchedulerFactory 实例以某一预定义键存放于 ServletContext 中。

早期 Quartz 版本中的 QuartzInitializerServlet

QuartzInitializerServlet 在早期版本的框架中就出现了。在以往版本中,StdSchedulerFactory 不会存放到 ServletContext 中。Sheduler 在 Servlet 的 init() 方法中初始化后即启动。欲从你的代码中获取 Scheduler 实例,你必须使用 StdSchedulerFactory 的某个 get 方法访问该 Servlet  创建的 Scheduler。从 ServletContext 中访问 Scheduler 的改变是在 1.5 版中加进来的。

你可在代码 13.1 的 init() 方法结束部分看出来。一旦工厂被存入 ServletContext,有多种方式可以获取访问到它。最简单的方式,尤其是你在用 Struts 框架的时候,是使用 request 对象。代码 13.3 展示了一个 Struts Action 类,叫做 StartSchedulerAction。当这个 Action 被调用(假定是通过 /startscheduler.do 这样的 URL 来访问),SchedulerFactory 就能获取取,接着可以调用 getScheduler() 方法。

代码 13.3. SchedulerFactory 和 Scheduler 能简单的被访问
 1import javax.servlet.ServletContext;
 2import javax.servlet.http.HttpServletRequest;
 3import javax.servlet.http.HttpServletResponse;
 4
 5import org.apache.struts.action.Action;
 6import org.apache.struts.action.ActionForm;
 7import org.apache.struts.action.ActionForward;
 8import org.apache.struts.action.ActionMapping;
 9import org.cavaness.jobconsole.web.QuartzFactoryServlet;
10import org.cavaness.jobconsole.web.WebConstants;
11import org.quartz.Scheduler;
12import org.quartz.impl.StdSchedulerFactory;
13
14public class StartSchedulerAction extends Action {
15    public ActionForward execute(ActionMapping mapping,
16    ActionForm form, HttpServletRequest request,
17    HttpServletResponse response) throws Exception {
18
19         // Retrieve the ServletContext
20         ServletContext ctx =
21              request.getSession().getServletContext();
22
23         // Retrieve the factory from the ServletContext
24         StdSchedulerFactory factory =
25               (StdSchedulerFactory)
26              ctx.getAttribute(
27                 QuartzFactoryServlet.QUARTZ_FACTORY_KEY);
28
29         // Retrieve the scheduler from the factory
30         Scheduler scheduler = factory.getScheduler();
31
32         // Start the scheduler
33         scheduler.start();
34
35         // Forward to success page
36         return mapping.findForward(WebConstants.SUCCESS);
37    }
38}

当从 SchedulerFactory 获取到 Scheduler 之后,你就可以按正常方式般调用 Scheduler 实例的方法。在代码 13.3 中,Scheduler 是使用 start() 方法来启动的,这是你所习惯的。

把 StdSchedulerFactory 存于 ServletContext 中的优点是避免了你重复创建它。实际上,你可以使得访问 Scheduler 甚至更简单,做法是把所有访问 ServletContext 和创建 Scheduler 的逻辑放到一个工具类中。代码 13.4 展示了这样一个名为 ActionUtil 的类,它简化了获得一个 Scheduler 对象的引用。

代码 13.4. ActionUtil 类方便了访问 Scheduler
 1import javax.servlet.ServletContext;
 2import javax.servlet.http.HttpServletRequest;
 3
 4import org.quartz.Scheduler;
 5import org.quartz.SchedulerException;
 6import org.quartz.impl.StdSchedulerFactory;
 7
 8public class ActionUtil {
 9
10    public static Scheduler getScheduler(HttpServletRequest request)
11         throws SchedulerException {
12
13         ServletContext ctx =
14              request.getSession().getServletContext();
15
16         StdSchedulerFactory factory =
17               (StdSchedulerFactory) ctx.getAttribute(
18               QuartzFactoryServlet.QUARTZ_FACTORY_KEY);
19
20         return factory.getScheduler();
21    }
22}

你能使用 ActionUtil.getScheduler() 方法很方便的获取到 Scheduler 实例。代码 13.3 中接下来的片断就是类 StartSchedulerAction 如何使用 Action.getScheduler() 方法了:
 1public class StartSchedulerAction extends Action {
 2    public ActionForward execute(ActionMapping mapping,
 3    ActionForm form, HttpServletRequest request,
 4    HttpServletResponse response) throws Exception {
 5
 6         // Retrieve the scheduler from the factory
 7         Scheduler scheduler = ActionUtil.getScheduler();
 8
 9         // Start the scheduler
10         scheduler.start();
11
12         // Forward to success page
13         return mapping.findForward(WebConstants.SUCCESS);
14
15    }
16}

代码 13.4 中的 ActionUtil 并非 Quartz 框架的一部份,但它或许会被加入到将来的版本中。你可在你的应用中需要的时候加入相同的东西。 永久链接 https://yanbin.blog/quartz-job-scheduling-framework-13-3/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。