·在 J2EE 应用服务器中运行 Quartz
作为 J2EE 客户端运行 Quartz 比运行为外部 J2SE 应用程序稍显繁琐。这主要是因为部署一个应用到容器中有点了儿复杂,J2EE 规范对容器中的组件会有些约束。其中最大的原则之一就是涉及到该由谁来创建线程。因为 J2EE 容器有责任去管理所有资源,所以它并非允许谁想谁就能创建线程的。假如是这样的话,容器就会要更艰难的去管理环境和保证一切稳定性。Quartz 会创建自己的工作者线程,所以你必须依照一些步骤来保证它能正常的运转。
确保代像代码 10.1 那样的一个无状态会话 Bean 已部署到容器中。最简单的部署 Quartz 到容器中的方式是构建一个包含所必须文件的 WAR 包,然后使用管理工具或 Eclipse 部署这个 Web 应用到容器中。
这个 Web 应用的目录结构像其他任何 Web 应用是一样的。你必须添加以下文件至其中:
·web.xml (放置到 WEB-INF 下)
·quartz.properties (放置在 WEB-INF/classes 下)
·quartz_jobs.xml (放置在 WEB-INF/classes 下)
·Quartz 二进制包 (放置在 WEB-INF/lib 下)
·所需第三方包 (放置在 WEB-INF/lib 下)
因为正在构建一个 Web 应用,所以要加入一个必备的 web.xml 作为部署描述文件。代码10.4 中显示了我们要安装到容器中的客户端应用的 web.xml 文件。
代码 10.4. Quartz J2EE 客户端程序的 web.xml 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>QuartzServlet</servlet-name> <servlet-class> org.quartz.ee.servlet.QuartzInitializerServlet </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>QuartzServlet</servlet-name> <url-pattern>/servlet/QuartzServlet</url-pattern> </servlet-mapping> </web-app> |
Quartz 框架包含有一个名为 QuartzInitializerServlet 的 Java Servlet,当被调用时它会初始化 Quartz 调度器并加载 Job 信息。在代码 10.4 中, 我们看到有设置 <load-on-startup> 标记值为 1,这指示着在容器启动的时候这个 servlet 会被自动加载并初始化。通过使用这个 servlet 去启动 Quartz 调度器,我们规避了容器中创建线程的约束,因为容器将允许 servlet 去创建用户线程的。
加入 QuartzInitializerListerner 到 Quartz 中 不久前,一个新的名为 QuartzInitializerListener 被加入到 Quartz 中来,它实现了 javax.servlet.ServletContextListener 接口。前面也有提过,这个类可用来替代 QuartzInitializerServlet 类。 |
接下来,你需要把标准的 quartz.properties 文件放入到 Web 应用的 WEB-INF/classes 目录中去。在这里的这个文件没什么特别的;实质上,这一步与前面同类的操作是一样的。然而,我们这里使用到 JobInitializationPluin (这在第八章,"使用 Quartz 插件",它设计为从 XML 文件中加载 Job 信息)。默认情况下,这个插件查找一个叫做 quartz_jobs.xml 文件并从中加载所配置的 Job。如第八章描述的,使用这一特定的插件可以避免你写加载作业的代码,且在代码改变时不得不重新编译。quartz_jobs.xml 的内容如 代码 10.5 所示。
代码 10.5. J2EE 客户端所用的 quartz_jobs.xml 文件
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 |
<?xml version='1.0' encoding='utf-8'?> <quartz> <job> <job-detail> <name>HelloWorldJob</name> <group>DEFAULT</group> <job-class>org.quartz.jobs.ee.ejb.EJBInvokerJob</job-class> <volatility>false</volatility> <durability>false</durability> <recover>false</recover> <job-data-map allows-transient-data="true"> <entry> <key>ejb</key> <value>ejb/Test</value> </entry> <entry> <key>java.naming.factory.initial</key> <value>org.openejb.client.RemoteInitialContextFactory</value> </entry> <entry> <key>java.naming.provider.url</key> <value>127.0.0.1:4201</value> </entry> <entry> <key>method</key> <value>helloWorld</value> </entry> <entry> <key>java.naming.security.principal</key> <value>system</value> </entry> <entry> <key>java.naming.security.credentials</key> <value>manager</value> </entry> </job-data-map> </job-detail> <trigger> <simple> <name>helloWorldTrigger</name> <group>DEFAULT</group> <job-name>HelloWorldJob</job-name> <job-group>DEFAULT</job-group> <start-time>2005-06-10 6:10:00 PM</start-time> <!- repeat indefinitely every 10 seconds > <repeat-count>-1</repeat-count> <repeat-interval>10000</repeat-interval> </simple> </trigger> </job> </quartz> |
你能看出在代码 10.5 中,我们仍然使用 EJBInvokerJob,只是声明在了 quartz_jobs.xml 文件中了。
在 quartz.properties 中指定插件 第八章已讲过,在使用 Quartz 插件就必须在 quartz.properties 文件中指定相应的插件信息。对于 JobInitialzationPluin,你必须在这个属性文件中加入下面一行代码: org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin |
上面的文件都配置好后,就可以构建一个 WAR 文件并部署到你的容器中。当容器启动之后,就会加载那个 servlet 并初化,进而启动了调度器。调度器利用 JobInitializerPluin 去从 quartz_jobs.xml 文件中加载作业信息。自此,EJBInvokerJob 就会调用 EJB 上的 helloWorld() 方法了。
·包含 J2EE 客户端 JAR 包
在打包 J2EE 客户程序时,你需要把所需的特定于服务器的 J2EE 客户端 JAR 包打进来。针对不同的容器会有所不同,你需要参照具体文档予于决定。在构建一个独立运行的 Quartz 应用时,你还要加入所需的 Quartz 包。
二:使用 J2EE 容器的数据源
直到此刻,我们有意没去提到 JobStores 和 DataSources。在第六章,"作业存储和持久化",你已经学到可以把作业信息存储在内存中,或者假你需要作业信息在两次程序重启之间能持久保存下来,你就可以把作业信息存储到关系型数据库中。存在有两种类型的 JDBC 作业存储方式:
·JobStoreTX 在持久化操作过程中自己管理自己的事特
·JobStoreCMT 在持久化操作过程中技术容器管理事物(CMT)
如果你使用了 J2EE 容器并选择了上面的种类型的 JDBC JobStores,这时候你最好应该用容器提供的数据源。参考前面第六章,当在 J2EE 容器中使用 JDBC JobStores 时如何设置 quartz.properties 文件。
三:使用其他的 J2EE 资源
当部署 Quartz 到 J2EE 容器中,你可以利用 J2EE 组件可用的其他资源。例如,假如你需要发送 email,一种途径是得用 Quartz 的 SendMailJob,它依赖于 JavaMail。另一可用途径是,假如你把 Quartz 部署在容器中,能使用所有 J2EE 服务器都可提供的 mail session 资源,当然,前提是你在容器中已配置好的 mail session。那是作为 J2EE 客户端来部署 Quartz 好处之一。
1 2 3 4 5 6 7 |
InitialContext initialContext = new InitialContext(); Session session = (Session) initialContext.lookup(urlToMailSession); Message msg = new MimeMessage(session); // ... build up msg Transport.send(msg); |
四:EJB 2.1 规范:最后的曙光
在 EJB 2.1 的第 22 章中讨论到企业 JavaBean 的一个新的特性,定时器服务。这是一个容器管理的服务,给予需要基于时间事件的组件回调服务。实质上就是 EJB 能通过这一服务注册他们自己,当到了它们要执行的时间时就会接收到一个通知。定时器服务是被 EJB 容器实现并管理着的。现在还不知道 J2EE 厂商还要在那些规范后面加上多少功能。有些人争辩说 EJB 定时器的提议内容还不充分,同样的原因,java.util.Timer 类也不足以真正应付调度程序。最好也看看 EJB 的架构规范,可加入对框架的插件支持,例如 Quartz 就可以用来增强定时器服务的灵活性。
本文链接 https://yanbin.blog/quartz-job-scheduling-framework-10-2/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
谢谢分享了!
第4章怎么不译了,直接跳到第9章了。
下面紧接着就会译第四章的,学以致用,工作中要用到前面所译章节内容,所以就先照顾了。自私一下,呵呵!