如何调度Java web开发中的任务

  作者:bea

以下示例展示了在web应用中,如何使用Quartz来创建一个任务调度框架。这个示例还使用了Struts Action framework 插件,以便在web应用启动时初始化任务调度机制。Struts是最常见的MVC框架,为大多数开发人员所熟悉。当然除此之外还有许多框架可以协助在web应用中实现MVC模式。 启动时初始化任务调度器 我们首先要做的是建立一个Struts插件,让它在容器启动时创建我们的任务调度器。在以下例子中,我们选择Tomcat作为web应用容器,不过这
以下示例展示了在web应用中,如何使用Quartz来创建一个任务调度框架。这个示例还使用了Struts Action framework 插件,以便在web应用启动时初始化任务调度机制。Struts是最常见的MVC框架,为大多数开发人员所熟悉。当然除此之外还有许多框架可以协助在web应用中实现MVC模式。

启动时初始化任务调度器

我们首先要做的是建立一个Struts插件,让它在容器启动时创建我们的任务调度器。在以下例子中,我们选择Tomcat作为web应用容器,不过这些示例在其他容器中也应当可以运行。我们要创建一个Struts插件类,并在struts-config.xml中加入几行代码以使之可以工作。

这个插件有两个可配置的初始化参数:startOnLoad指定是否要在容器启动时立即启动任务调度器,而 startupDelay指定启动任务调度器之前的等待时间。启动延时很有用,因为我们可能需要首先执行一些更重要的初始化步骤。此外还可以使用listener机制,以更复杂的方式来通知SchedulerPlugIn何时启动Quartz Scheduler。





我们要创建的是一个实现Struts插件接口org.apache.struts.action.PlugIn的单子类SchedulerPlugIn。Struts会按照配置文件中出现的顺序初始化各个插件。要特别注意的是init()方法中的代码,在此我们初始化了所需的Quartz对象,并得到Scheduler。我们的任务信息就要提交到此org.quartz.Scheduler对象,后者将在随后讨论。Scheduler对象由Quartz servlet根据其配置初始化,就像Struts初始化它的ActionServlet类一样。让我们来看init()方法:

public void init(ActionServlet actionServlet,
ModuleConfig moduleConfig) {
System.out.println("Initializing Scheduler PlugIn for Jobs!");
// Retrieve the ServletContext
// 获取ServletContext
ServletContext ctx = actionServlet.getServletContext();
// The Quartz Scheduler
// Quartz Scheduler对象
Scheduler scheduler = null;
// Retrieve the factory from the ServletContext.
// It will be put there by the Quartz Servlet
// 从ServletContext取得由Quartz Servlet放置在此的factory对象。
StdSchedulerFactory factory =(StdSchedulerFactory)
ctx.getAttribute(QuartzInitializerServlet.QUARTZ_FACTORY_KEY);
try{
// Retrieve the scheduler from the factory
// 从factory取得scheduler
scheduler = factory.getScheduler();
// Start the scheduler in case, it isn't started yet
// 如果scheduler尚未启动,则启动它
if (m_startOnLoad != null &&
m_startOnLoad.equals(Boolean.TRUE.toString())){
System.out.println("Scheduler Will start in " +
m_startupDelayString + " milliseconds!");
//wait the specified amount of time before
// starting the process.
// 在启动之前等待指定长度的时间
Thread delayedScheduler =
new Thread(new DelayedSchedulerStarted (
scheduler, m_startupDelay));
//give the scheduler a name. All good code needs a name
//给任务调度器命名。好的代码总该有名字!
delayedScheduler.setName("Delayed_Scheduler");
//Start out scheduler
//启动任务调度器
delayedScheduler.start();
}
} catch (Exception e){
e.printStackTrace();
}
sm_scheduler = scheduler;
}

配置过程的第二步是在web.xml中加入用来初始化Quartz servlet(org.quartz.ee.servlet.QuartzInitializerServlet)的内容,因为需要它将SchedulerFactory添加到ServletContext中,以便在我们的Struts插件中可以访问。SchedulerFactory就是我们在Struts插件中获得Scheduler对象的来源。除了struts-config.xml 和web.xml之外,还要在web应用的classes目录下放置一个quartz.properties文件。此文件的位置也可以在web.xml中作为QuartzInitializerServlet的启动参数来指定。


QuartzInitializer
Quartz Initializer Servlet
org.quartz.ee.servlet.QuartzInitializerServlet
1
shutdown-on-unload
true
start-scheduler-on-load
false


这里其实完全可以不使用Struts和SchedulerPlugIn,但如果将来决定要以其它的任务调度框架替换Quartz的话,额外的抽象层就很有用了。长远看来,让一切保持松散耦合总会使工作变得容易些。如果你使用其它MVC框架,也可以用SchedulerPlugIn.init()方法中的代码达到同样的效果。此外,还可以用Servlet 2.3规范中的ServletContextListener来实现同样的初始化过程。

此为止web应用已配置完毕,我们可以创建一个.war文件并部署到服务器上,从控制台观察SchedulerPlugIn的输出信息。然而在此之前,让我们先看看如何向任务调度器提交一项任务。

我们可以从web应用中的任何类访问SchedulerPlugIn的唯一实例,并调度一些要执行的工作。首先需要一个Trigger(触发器)对象来告诉任务何时运行、每隔多久运行一次。Quartz支持多种触发器,在这个例子中我们使用CronTrigger。
Trigger trigger = new CronTrigger("trigger1", "group1");
trigger.setCronExpression("0 0 15 ? * WED");

以上的触发器会在每周三的下午3点执行指定任务。现在我们只要创建一个JobDetail对象,并把它和上面的触发器一起传递给SchedulerPlugIn的scheduleWork()方法。
JobDetail jobDetail =
new JobDetail("Hello World Job",
"Hello World Group",
HelloWorld.class,
true, true, true);
//Schedule The work
//调度这项任务
SchedulerPlugIn.scheduleWork(scheduledJobDetail, trigger);

实际工作在何处?

至此我们已决定Trigger,可以开始调度工作了。看上去一切都已完成,但实际上我们只是调度了一项任务,还有最重要的一步有待完成。注意HelloWorld.class作为参数传递给了JobDetail的构造函数。这个类就是实际完成工作的地方。HelloWorld继承了Quartz的Job类,并覆盖了execute()方法。当任务管理器决定运行这个任务时,execute()方法将被调用。来看代码:
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
//extend the proper Quartz class
//继承适当的Quartz类
public class HelloWorld extends Job {
//override the execute method
//覆盖execute方法
public void execute(JobExecutionContext context) {
// Every job has it's own job detail
//每个Job都有独立的JobDetail
JobDetail jobDetail = context.getJobDetail();
// The name is defined in the job definition
//name在Job定义中指定
String jobName = jobDetail.getName();
//Every job has a Job Data map for storing extra information
//每个Job都有一个Job Data map来存放额外的信息
JobDataMap dataMap = jobDetail.getJobDataMap();

System.out.println("Hello World!!!");
}
}

出于测试的目的,你可能希望将触发器的频率调的高一点,以便观察到HelloWorld的动作。毕竟,你不想一直等到凌晨2点才能确定调度的任务确实运行了。相反,你可能需要一个每隔10秒运行的触发器:
Trigger trigger = new SimpleTrigger("trigger1", "group1");
trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
trigger.setRepeatInterval(10000L); // milliseconds毫秒

注意,这个触发器没有使用类cron的语法。Quartz有大量各类的选项和配置方法,可适用于任何任务调度的需要。

其它计时方式的配置

Quartz提供了多种调度任务的方式。CronTrigger可能是最复杂的一种,不过还有其它的选择。大多数触发器可以由Quartz提供的TriggerUtils类创建。以下是一些常见的触发器的例子。如谚语所言,条条大路通罗马!
每天凌晨2:22触发的触发器
// 方法一:使用makeDailyTrigger
Trigger trigger = TriggerUtils.makeDailyTrigger(2, 22);
trigger.setName("trigger1");
trigger.setGroup("group1");

// 方法二:使用CronTrigger
Trigger trigger = new CronTrigger("trigger1", "group1");
trigger.setCronExpression("0 22 2 * * ?");

每5秒执行一次的触发器
/**
* 方法一:makeSecondlyTrigger
* 注意以下代码将创建一个立即启动的触发器。要控制启动时间,使用
* trigger.setStartTime(Date)方法。
*/
Trigger trigger = TriggerUtils.makeSecondlyTrigger(5);
trigger.setName("MyFiveSecondTrigger");
trigger.setGroup("MyTriggerGroup");

/*
*
* 方法二:设置SimpleTrigger的重复次数和间隔时间。
* 注意以下代码将创建一个立即启动的触发器。要控制启动时间,使用
* trigger.setStartTime(Date)方法。
*/
Trigger trigger = new SimpleTrigger("trigger1", "group1");
trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
trigger.setRepeatInterval(5000L); // milliseconds

按间隔时间运行任务
Trigger trigger = new SimpleTrigger("trigger1", "group1");
// 24 hours * 60(minutes per hour) *
// 60(seconds per minute) * 1000(milliseconds per second)
// 24小时 * 60(分钟每小时) * 60(秒每分钟)* 1000(毫秒每秒钟)
trigger.setRepeatInterval(24L * 60L * 60L * 1000L);

结论
在这个演示中,我们只接触了Quartz框架的一些初级功能。记住,Java 5 和J2EE 5也有自己的任务调度机制,但是它们不像Quartz那样灵活易用。Quartz是目前唯一的开源Java任务调度框架,它的确为开发者的锦囊中增加了很有用的内容。你可从Open Symphony下载Quartz,并得到一份很好的教程和使用说明。 有用  |  无用

猜你喜欢