Files
spring-net/doc/reference/src/scheduling.xml

230 lines
10 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<!--
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<chapter xml:id="scheduling" xmlns="http://docbook.org/ns/docbook" version="5">
<title>Scheduling and Thread Pooling</title>
<section xml:id="scheduling-introduction">
<title>Introduction</title>
<para>The Spring Framework features integration classes for scheduling
support. Currently, Spring supports the Quartz Scheduler (<ulink
url="http://quartznet.sourceforge.net/"></ulink>). The scheduler is set up
using a <literal>IFactoryObject</literal> with optional
references to <literal>Trigger</literal> instances, respectively.
Furthermore, a convenience class for both the Quartz Scheduler is
available that allows you to invoke a method of an existing target
object.</para>
</section>
<section xml:id="scheduling-quartz">
<title>Using the Quartz.NET Scheduler</title>
<para>Quartz uses <literal>Trigger</literal>,
<literal>Job</literal> and <literal>JobDetail</literal> objects to
realize scheduling of all kinds of jobs. For the basic concepts behind
Quartz, have a look at <ulink
url="http://quartznet.sourceforge.net/"></ulink>. For convenience
purposes, Spring offers a couple of classes that simplify the usage of
Quartz within Spring-based applications.</para>
<section xml:id="scheduling-quartz-jobdetail">
<title>Using the JobDetailObject</title>
<para><literal>JobDetail</literal> objects contain all information
needed to run a job. The Spring Framework provides a
<literal>JobDetailObject</literal> that makes the
<literal>JobDetail</literal> easier to configure and with sensible
defaults. Let's have a look at an example:</para>
<programlisting language="myxml">
&lt;object name="ExampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="JobType" value="Example.Quartz.ExampleJob, Example.Quartz" /&gt;
&lt;property name="JobDataAsMap"&gt;
&lt;dictionary&gt;
&lt;entry key="Timeout" value="5" /&gt;
&lt;/dictionary&gt;
&lt;/property&gt;
&lt;/object&gt;</programlisting>
<para>The job detail object has all information it needs to run the job
(<literal>ExampleJob</literal>). The timeout is specified in the job
data dictionary. The job data dictonary is available through the
<literal>JobExecutionContext</literal> (passed to you at execution
time), but the <literal>JobDetailObject</literal> also maps the
properties from the job data map to properties of the actual job. So in
this case, if the <literal>ExampleJob</literal> contains a property
named <literal>Timeout</literal>, the
<literal>JobDetailObject</literal> will automatically apply
it:</para>
<programlisting language="csharp">namespace Example.Quartz;
public class ExampleJob extends QuartzJobObject {
private int timeout;
/// &lt;summary&gt;
/// Setter called after the ExampleJob is instantiated
/// with the value from the JobDetailObject (5)
/// &lt;/summary&gt;
public int Timeout {
set { timeout = value; };
}
protected override void ExecuteInternal(JobExecutionContext context) {
<lineannotation>// do the actual work</lineannotation>
}
}</programlisting>
<para>All additional settings from the job detail object are of course
available to you as well.</para>
<para><emphasis>Note: Using the <literal>name</literal> and
<literal>group</literal> properties, you can modify the name and the
group of the job, respectively. By default, the name of the job matches
the object name of the job detail object (in the example above, this is
<literal>ExampleJob</literal>).</emphasis></para>
</section>
<section xml:id="scheduling-quartz-method-invoking-job">
<title>Using the
<literal>MethodInvokingJobDetailFactoryObject</literal></title>
<para>Often you just need to invoke a method on a specific object. Using
the <literal>MethodInvokingJobDetailFactoryObject</literal> you can
do exactly this:</para>
<programlisting language="myxml">&lt;object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="TargetObject" ref="ExampleBusinessObject" /&gt;
&lt;property name="TargetMethod" value="DoIt" /&gt;
&lt;/object&gt;</programlisting>
<para>The above example will result in the <literal>doIt</literal>
method being called on the <literal>exampleBusinessObject</literal>
method (see below):</para>
<programlisting language="csharp">public class ExampleBusinessObject {
<lineannotation>// properties and collaborators</lineannotation>
public void DoIt() {
<lineannotation>// do the actual work</lineannotation>
}
}</programlisting>
<programlisting language="myxml">
&lt;object id="ExampleBusinessObject" type="Examples.BusinessObjects.ExampleBusinessObject, Examples.BusinessObjects"/&gt;</programlisting>
<para>Using the
<literal>MethodInvokingJobDetailFactoryObject</literal>, you don't
need to create one-line jobs that just invoke a method, and you only
need to create the actual business object and wire up the detail
object.</para>
<para>By default, Quartz Jobs are stateless, resulting in the
possibility of jobs interfering with each other. If you specify two
triggers for the same <literal>JobDetail</literal>, it might be
possible that before the first job has finished, the second one will
start. If <literal>JobDetail</literal> classes implement the
<literal>Stateful</literal> interface, this won't happen.
The second job will not start before the first one has finished. To make
jobs resulting from the
<literal>MethodInvokingJobDetailFactoryObject</literal>
non-concurrent, set the <literal>concurrent</literal> flag to
<literal>false</literal>.</para>
<programlisting language="myxml">&lt;object id="JobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="TargetObject" ref="ExampleBusinessObject" /&gt;
&lt;property name="TargetMethod" value="DoIt" /&gt;
&lt;property name="Concurrent" value="false" /&gt;
&lt;/object&gt;
</programlisting>
<note>
<para>By default, jobs will run in a concurrent fashion. </para>
<para>Also note that when using MethodInvokingJobDetailFactoryObject
you can't use database persistence for Jobs. See the class
documentation for additional details.</para>
</note>
</section>
<section xml:id="scheduling-quartz-cron">
<title>Wiring up jobs using triggers and the
<literal>SchedulerFactoryObject</literal></title>
<para>We've created job details and jobs. We've also reviewed the
convenience class that allows to you invoke a method on a specific
object. Of course, we still need to schedule the jobs themselves. This
is done using triggers and a
<literal>SchedulerFactoryObject</literal>. Several triggers are
available within Quartz. Spring offers two subclassed triggers with
convenient defaults: <literal>CronTriggerObject</literal> and
<literal>SimpleTriggerObject</literal></para>
<para>Triggers need to be scheduled. Spring offers a
<literal>SchedulerFactoryObject</literal> that exposes triggers to
be set as properties. <literal>SchedulerFactoryObject</literal>
schedules the actual jobs with those triggers.</para>
<para>Find below a couple of examples:</para>
<programlisting language="myxml">&lt;object id="SimpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz"&gt;
&lt;!-- see the example of method invoking job above --&gt;
&lt;property name="JobDetail" ref="ExampleJob" /&gt;
&lt;!-- 10 seconds --&gt;
&lt;property name="StartDelay" value="10s" /&gt;
&lt;!-- repeat every 50 seconds --&gt;
&lt;property name="RepeatInterval" value="50s" /&gt;
&lt;/object&gt;
&lt;object id="CronTrigger" type="Spring.Scheduling.Quartz.CronTriggerObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="JobDetail" ref="ExampleJob" /&gt;
&lt;!-- run every morning at 6 AM --&gt;
&lt;property name="CronExpressionString" value="0 0 6 * * ?" /&gt;
&lt;/object&gt;
</programlisting>
<para>Now we've set up two triggers, one running every 50 seconds with a
starting delay of 10 seconds and one every morning at 6 AM. To finalize
everything, we need to set up the
<literal>SchedulerFactoryObject</literal>:</para>
<programlisting language="myxml">&lt;object id="quartzSchedulerFactory" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz"&gt;
&lt;property name="triggers"&gt;
&lt;list&gt;
&lt;ref object="CronTrigger" /&gt;
&lt;ref object="SimpleTrigger" /&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/object&gt;
</programlisting>
<para>More properties are available for the
<literal>SchedulerFactoryObjecct</literal> for you to set, such as
the calendars used by the job details, properties to customize Quartz
with, etc. Have a look at the <ulink
url="http://static.springframework.org/spring/docs/2.5.x/api/org/springframework/scheduling/quartz/SchedulerFactoryBean.html">SchedulerFactoryObject
SDK docs</ulink> for more information.</para>
</section>
</section>
</chapter>