Files
spring-net/doc/reference/src/scheduling.xml
2008-11-05 23:04:25 +00:00

231 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 version="5" xml:id="scheduling" xmlns="http://docbook.org/ns/docbook"
xmlns:ns5="http://www.w3.org/1999/xhtml"
xmlns:ns42="http://www.w3.org/2000/svg"
xmlns:ns4="http://www.w3.org/1999/xlink"
xmlns:ns3="http://www.w3.org/1998/Math/MathML"
xmlns:ns="http://docbook.org/ns/docbook">
<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/" />). The scheduler is set up using
a <literal>IFactoryObject</literal> with optional references to
<literal>Trigger</literal> instances, respectively. Furthermore, a
convenience class for 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/" />. 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>