1116 lines
57 KiB
XML
1116 lines
57 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="aop-quickstart" xmlns="http://docbook.org/ns/docbook" version="5">
|
|
<title>AOP Guide</title>
|
|
|
|
<sect1 xml:id="aop-quickstart-introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para>This is an introductory guide to Aspect Oriented Programming (AOP)
|
|
with Spring.NET.</para>
|
|
|
|
<para>This guide assumes little to no prior experience of having
|
|
<emphasis>used</emphasis> Spring.NET AOP on the part of the reader.
|
|
However, it <emphasis>does</emphasis> assume a certain familiarity with
|
|
the terminology of AOP in general. It is probably better if you have read
|
|
(or at least have skimmed through) the AOP section of the reference
|
|
documentation beforehand, so that you are familiar with a) just what AOP
|
|
is, b) what problems AOP is addressing, and c) what the AOP concepts of
|
|
<literal>advice</literal>, <literal>pointcut</literal>, and
|
|
<literal>joinpoint</literal> actually mean... this guide spends absolutely
|
|
zero time defining those terms. Having said all that, if you are the kind
|
|
of developer who learns best by example, then by all means follow along...
|
|
you can always consult the reference documentation as the need arises (see
|
|
<xref linkend="aop-introduction-defn" />).</para>
|
|
|
|
<para><emphasis> The examples in this guide are <emphasis
|
|
role="bold">intentionally</emphasis> simplistic. One of the core aims of
|
|
this guide is to get you up and running with Spring.NET's flavor of AOP in
|
|
as short a time as possible. Having to comprehend even a simple object
|
|
model in order to understand the AOP examples would not be conducive to
|
|
learning Spring.NET AOP. It is left as an exercise for the reader to take
|
|
the concepts learned from this guide and apply them to his or her own code
|
|
base. Again, having said all of that, this guide concludes with a number
|
|
of cookbook-style AOP 'recipes' that illustrate the application of
|
|
Spring.NET's AOP offering in a real world context; additionally, the
|
|
Spring.NET reference application contains a number of Spring.NET AOP
|
|
aspects particular to it's own domain model (see <xref
|
|
linkend="springair" />). </emphasis></para>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="aop-quickstart-basics">
|
|
<title>The basics</title>
|
|
|
|
<para>This initial section introduces the basics of defining and then
|
|
applying some simple advice.</para>
|
|
|
|
<sect2 xml:id="aop-quickstart-basics-advice">
|
|
<title>Applying advice</title>
|
|
|
|
<para>Lets see (a very basic) example of using Spring.NET AOP. The
|
|
following example code simply applies advice that writes the details of
|
|
an advised method call to the system console. Admittedly, this is not a
|
|
particularly compelling or even useful application of AOP, but having
|
|
worked through the example, you will then hopefully be able to see how
|
|
to apply your own custom advice to perform useful work (transaction
|
|
management, auditing, security enforcement, thread safety, etc).</para>
|
|
|
|
<para>Before looking at the AOP code proper lets quickly look at the
|
|
domain classes that are the target of the advice (in Spring.NET AOP
|
|
terminology, an instance of the following class is going to be the
|
|
<emphasis>advised object</emphasis>.</para>
|
|
|
|
<programlisting language="csharp">public interface ICommand
|
|
{
|
|
object Execute(object context);
|
|
}
|
|
|
|
public class ServiceCommand : ICommand
|
|
{
|
|
public object Execute(object context)
|
|
{
|
|
Console.Out.WriteLine("Service implementation : [{0}]", context);
|
|
return null;
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Find below the advice that is going to be applied to the
|
|
<literal>object Execute(object context)</literal> method of the
|
|
<literal>ServiceCommand</literal> class. As you can see, this is an
|
|
example of <emphasis>around advice</emphasis> (see <xref
|
|
linkend="aop-introduction-advice-types" />).</para>
|
|
|
|
<programlisting language="csharp"> public class ConsoleLoggingAroundAdvice : IMethodInterceptor
|
|
{
|
|
public object Invoke(IMethodInvocation invocation)
|
|
{
|
|
Console.Out.WriteLine("Advice executing; calling the advised method..."); <co
|
|
id="aop-quickstart-basics-advice-around-1" />
|
|
object returnValue = invocation.Proceed(); <co
|
|
id="aop-quickstart-basics-advice-around-2" /> <co
|
|
id="aop-quickstart-basics-advice-around-3" />
|
|
Console.Out.WriteLine("Advice executed; advised method returned " + returnValue); <co
|
|
id="aop-quickstart-basics-advice-around-4" />
|
|
return returnValue; <co id="aop-quickstart-basics-advice-around-5" />
|
|
}
|
|
}</programlisting>
|
|
|
|
<calloutlist>
|
|
<callout arearefs="aop-quickstart-basics-advice-around-1">
|
|
Some simple code that merely prints out the fact that the advice is executing.
|
|
</callout>
|
|
|
|
<callout arearefs="aop-quickstart-basics-advice-around-2">
|
|
The advised method is invoked.
|
|
</callout>
|
|
|
|
<callout arearefs="aop-quickstart-basics-advice-around-3">
|
|
The return value is captured in the
|
|
|
|
<literal>returnValue</literal>
|
|
|
|
variable.
|
|
</callout>
|
|
|
|
<callout arearefs="aop-quickstart-basics-advice-around-4">
|
|
The value of the captured
|
|
|
|
<literal>returnValue</literal>
|
|
|
|
is printed out.
|
|
</callout>
|
|
|
|
<callout arearefs="aop-quickstart-basics-advice-around-5">
|
|
The previously captured
|
|
|
|
<literal>returnValue</literal>
|
|
|
|
is returned.
|
|
</callout>
|
|
</calloutlist>
|
|
|
|
<para>So thus far we have three artifacts: an interface
|
|
(<literal>ICommand</literal>); an implementation of said interface
|
|
(<literal>ServiceCommand</literal>); and some (trivial) advice
|
|
(encapsulated by the <literal>ConsoleLoggingAroundAdvice</literal>
|
|
class). All that remains is to actually apply the
|
|
<literal>ConsoleLoggingAroundAdvice</literal> advice to the
|
|
invocation of the <literal>Execute()</literal> method of the
|
|
<literal>ServiceCommand</literal> class. Lets look at how to effect
|
|
this programmatically...</para>
|
|
|
|
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
|
|
factory.AddAdvice(new ConsoleLoggingAroundAdvice());
|
|
ICommand command = (ICommand) factory.GetProxy();
|
|
command.Execute("This is the argument");</programlisting>
|
|
|
|
<para>The result of executing the above snippet of code will look
|
|
something like this...</para>
|
|
|
|
<programlisting> Advice executing; calling the advised method...
|
|
Service implementation : [This is the argument]
|
|
Advice executed; advised method returned </programlisting>
|
|
|
|
<para>The output shows that the advice (the
|
|
<literal>Console.Out</literal> statements from the
|
|
<literal>ConsoleLoggingAroundAdvice</literal> was applied
|
|
<emphasis>around</emphasis> the invocation of the advised method.</para>
|
|
|
|
<para>So what is happening here? The fact that the preceding code used a
|
|
class called <literal>ProxyFactory</literal> may have clued you in.
|
|
The constructor for the <literal>ProxyFactory</literal> class took
|
|
as an argument the object that we wanted to advise (in this case, an
|
|
instance of the <literal>ServiceCommand</literal> class). We then
|
|
added some advice (a <literal>ConsoleLoggingAroundAdvice</literal>
|
|
instance) using the <literal>AddAdvice()</literal> method of the
|
|
<literal>ProxyFactory</literal> instance. We then called the
|
|
<literal>GetProxy()</literal> method of the
|
|
<literal>ProxyFactory</literal> instance which gave us a proxy... an
|
|
(AOP) proxy that proxied the target object (the
|
|
<literal>ServiceCommand</literal> instance), and called the advice
|
|
(a single instance of the
|
|
<literal>ConsoleLoggingAroundAdvice</literal> in this case). When we
|
|
invoked the <literal>Execute(object context)</literal> method of the
|
|
proxy, the advice was <literal>'applied'</literal> (executed), as can be
|
|
seen from the attendant output.</para>
|
|
|
|
<para>The following image shows a graphical view of the flow of
|
|
execution through a Spring.NET AOP proxy.</para>
|
|
|
|
<mediaobject>
|
|
<imageobject>
|
|
<imagedata fileref="images/aop-chain.png" format="png" />
|
|
</imageobject>
|
|
</mediaobject>
|
|
|
|
<para>One thing to note here is that the AOP proxy that was returned
|
|
from the call to the <literal>GetProxy()</literal> method of the
|
|
<literal>ProxyFactory</literal> instance was cast to the
|
|
<literal>ICommand</literal> interface that the
|
|
<literal>ServiceCommand</literal> target object implemented. This is
|
|
very important... currently, Spring.NET's AOP implementation mandates
|
|
the use of an interface for advised objects. In short, this means that
|
|
in order for your classes to leverage Spring.NET's AOP support, those
|
|
classes that you wish to use with Spring.NET AOP <emphasis
|
|
role="bold">must</emphasis> implement at least one interface. In
|
|
practice this restriction is not as onerous as it sounds... in any case,
|
|
it is <emphasis>generally</emphasis> good practice to program to
|
|
interfaces anyway (support for applying advice to classes that do not
|
|
implement any interfaces is planned for a future point release of
|
|
Spring.NET AOP).</para>
|
|
|
|
<para>The remainder of this guide is concerned with fleshing out some of
|
|
the finer details of Spring.NET AOP, but basically speaking, that's
|
|
about it.</para>
|
|
|
|
<para>As a first example of fleshing out one of those finer details,
|
|
find below some Spring.NET XML configuration that does
|
|
<emphasis>exactly</emphasis> the same thing as the previous example; it
|
|
should also be added that this declarative style approach to Spring.NET
|
|
AOP is preferred to the programmatic style.</para>
|
|
|
|
<programlisting language="myxml"> <object id="consoleLoggingAroundAdvice"
|
|
type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"/>
|
|
<object id="myServiceObject" type="Spring.Aop.Framework.ProxyFactoryObject">
|
|
<property name="target">
|
|
<object id="myServiceObjectTarget"
|
|
type="Spring.Examples.AopQuickStart.ServiceCommand"/>
|
|
</property>
|
|
<property name="interceptorNames">
|
|
<list>
|
|
<value>consoleLoggingAroundAdvice</value>
|
|
</list>
|
|
</property>
|
|
</object></programlisting>
|
|
|
|
<programlisting language="csharp"> ICommand command = (ICommand) ctx["myServiceObject"];
|
|
command.Execute();</programlisting>
|
|
|
|
<para>Some comments are warranted concerning the above XML configuration
|
|
snippet. Firstly, note that the
|
|
<literal>ConsoleLoggingAroundAdvice</literal> is itself a plain
|
|
vanilla object, and is eligible for configuration just like any other
|
|
class... if the advice itself needed to be injected with any
|
|
dependencies, any such dependencies could be injected as normal.</para>
|
|
|
|
<para>Secondly, notice that the object definition corresponding to the
|
|
object that is retrieved from the IoC container is a
|
|
<literal>ProxyFactoryObject</literal>. The
|
|
<literal>ProxyFactoryObject</literal> class is an implementation of
|
|
the <literal>IFactoryObject</literal> interface;
|
|
<literal>IFactoryObject</literal> implementations are treated
|
|
specially by the Spring.NET IoC container... in this specific case, it
|
|
is not a reference to the <literal>ProxyFactoryObject</literal>
|
|
instance itself that is returned, but rather the object that the
|
|
<literal>ProxyFactoryObject</literal> produces. In this case, it
|
|
will be an advised instance of the <literal>ServiceCommand</literal>
|
|
class.</para>
|
|
|
|
<para>Thirdly, notice that the target of the
|
|
<literal>ProxyFactoryObject</literal> is an instance of the
|
|
<literal>ServiceCommand</literal> class; this is the object that is
|
|
going to be advised (i.e. invocations of its methods are going to be
|
|
intercepted). This object instance is defined as an inner object
|
|
definition... this is the preferred idiom for using the
|
|
<literal>ProxyFactoryObject</literal>, as it means that other
|
|
objects cannot acquire a reference to the raw object, but rather only
|
|
the advised object.</para>
|
|
|
|
<para>Finally, notice that the advice that is to be applied to the
|
|
target object is referred to by its object name in the list of the names
|
|
of interceptors for the <literal>ProxyFactoryObject</literal>'s
|
|
<literal>interceptorNames</literal> property. In this particular case,
|
|
there is only one instance of advice being applied... the
|
|
<literal>ConsoleLoggingAroundAdvice</literal> defined in an object
|
|
definition of the same name. The reason for using a list of object names
|
|
as opposed to references to the advice objects themselves is explained
|
|
in the reference documentation...</para>
|
|
|
|
<para><emphasis> '... if the <literal>ProxyFactoryObject</literal>'s
|
|
singleton property is set to false, it must be able to return
|
|
independent proxy instances. If any of the advisors is itself a
|
|
prototype, an independent instance would need to be returned, so it is
|
|
necessary to be able to obtain an instance of the prototype from the
|
|
context; holding a reference isn't sufficient.' </emphasis></para>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="aop-quickstart-basics-pointcuts">
|
|
<title>Using Pointcuts - the basics</title>
|
|
|
|
<para>The advice that was applied in the previous section was rather
|
|
indiscriminate with regard to which methods on the advised object were
|
|
to be advised... the <literal>ConsoleLoggingAroundAdvice</literal>
|
|
simply intercepted <emphasis role="bold">all</emphasis> methods (that
|
|
were part of an interface implementation) on the target object.</para>
|
|
|
|
<para>This is great for simple examples and suchlike, but not so great
|
|
when you only want certain methods of an object to be advised. For
|
|
example, you may only want those methods beginning with
|
|
<literal>'Start'</literal> to be advised; or you may only want those
|
|
methods that are called with specific runtime argument values to be
|
|
advised; or you may only want those methods that are decorated with a
|
|
<literal>Lockable</literal> attribute to be advised.</para>
|
|
|
|
<para>The mechanism that Spring.NET AOP uses to discriminate about where
|
|
advice is applied (i.e. which method invocations are intercepted) is
|
|
encapsulated by the <literal>IPointcut</literal> interface (see
|
|
<xref linkend="aop-pointcuts" />). Spring.NET provides many
|
|
out-of-the-box implementations of the <literal>IPointcut</literal>
|
|
interface... the implementation that is used if none is explicitly
|
|
supplied (as was the case with the first example) is the canonical
|
|
<literal>TruePointcut</literal> : as the name suggests, this
|
|
pointcut always matches, and hence <emphasis role="bold">all</emphasis>
|
|
methods that can be advised will be advised.</para>
|
|
|
|
<para>So let's change the configuration of the advice such that it is
|
|
only applied to methods that contain the letters
|
|
<literal>'Do'</literal>. We'll change the
|
|
<literal>ICommand</literal> interface (and it's attendant
|
|
implementation) to accommodate this...</para>
|
|
|
|
<programlisting language="csharp"> public interface ICommand
|
|
{
|
|
void Execute();
|
|
|
|
void DoExecute();
|
|
}
|
|
|
|
public class ServiceCommand : ICommand
|
|
{
|
|
public void Execute()
|
|
{
|
|
Console.Out.WriteLine("Service implementation : Execute()...");
|
|
}
|
|
|
|
public void DoExecute()
|
|
{
|
|
Console.Out.WriteLine("Service implementation : DoExecute()...");
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Please note that the advice itself (encapsulated within the
|
|
<literal>ConsoleLoggingAroundAdvice</literal> class) does not need
|
|
to change; we are changing <emphasis>where</emphasis> this advice is
|
|
applied, and not the advice itself.</para>
|
|
|
|
<para>Programmatic configuration of the advice, taking into account the
|
|
fact that we only want methods that contain the letters
|
|
<literal>'Do'</literal> to be advised, looks like this...</para>
|
|
|
|
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
|
|
factory.AddAdvisor(new DefaultPointcutAdvisor(
|
|
new SdkRegularExpressionMethodPointcut("Do"),
|
|
new ConsoleLoggingAroundAdvice()));
|
|
ICommand command = (ICommand) factory.GetProxy();
|
|
command.DoExecute();</programlisting>
|
|
|
|
<para>The result of executing the above snippet of code will look
|
|
something like this...</para>
|
|
|
|
<programlisting language="csharp"> Intercepted call : about to invoke next item in chain...
|
|
Service implementation...
|
|
Intercepted call : returned</programlisting>
|
|
|
|
<para>The output indicates that the advice was applied around the
|
|
invocation of the advised method, because the name of the method that
|
|
was executed contained the letters <literal>'Do'</literal>. Try changing
|
|
the pertinent code snippet to invoke the <literal>Execute()</literal>
|
|
method, like so...</para>
|
|
|
|
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
|
|
factory.AddAdvisor(
|
|
new DefaultPointcutAdvisor(
|
|
new SdkRegularExpressionMethodPointcut("Do"),
|
|
new ConsoleLoggingAroundAdvice()));
|
|
ICommand command = (ICommand) factory.GetProxy();
|
|
|
|
// note that there is no 'Do' in this method name
|
|
command.Execute();</programlisting>
|
|
|
|
<para>Run the code snippet again; you will see that the advice will not
|
|
be applied : the pointcut is not matched (the method name does not
|
|
contain the letters <literal>'Do'</literal>), resulting in the following
|
|
(unadvised) output...</para>
|
|
|
|
<programlisting>Service implementation...</programlisting>
|
|
|
|
<para>XML configuration that accomplishes exactly the same thing as the
|
|
previous programmatic configuration example can be seen below...</para>
|
|
|
|
<programlisting language="myxml"> <object id="consoleLoggingAroundAdvice"
|
|
type="Spring.Aop.Support.RegularExpressionMethodPointcutAdvisor">
|
|
<property name="pattern" value="Do"/>
|
|
<property name="advice">
|
|
<object type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"/>
|
|
</property>
|
|
</object>
|
|
<object id="myServiceObject"
|
|
type="Spring.Aop.Framework.ProxyFactoryObject">
|
|
<property name="target">
|
|
<object id="myServiceObjectTarget"
|
|
type="Spring.Examples.AopQuickStart.ServiceCommand"/>
|
|
</property>
|
|
<property name="interceptorNames">
|
|
<list>
|
|
<value>consoleLoggingAroundAdvice</value>
|
|
</list>
|
|
</property>
|
|
</object></programlisting>
|
|
|
|
<para>You'll will perhaps have noticed that this treatment of pointcuts
|
|
introduced the concept of an <literal>advisor</literal> (see <xref
|
|
linkend="aop-advisors" />). An advisor is nothing more the composition
|
|
of a pointcut (i.e. <emphasis>where</emphasis> advice is going to be
|
|
applied), and the advice itself (i.e. <emphasis>what</emphasis> is going
|
|
to happen at the interception point). The
|
|
<literal>consoleLoggingAroundAdvice</literal> object defines an advisor
|
|
that will apply the advice to all those methods of the advised object
|
|
that match the pattern <literal>'Do'</literal> (the pointcut). The
|
|
pattern to match against is supplied as a simple string value to the
|
|
<literal>pattern</literal> property of the
|
|
<literal>RegularExpressionMethodPointcutAdvisor</literal>
|
|
class.</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="aop-quickstart-going-deeper">
|
|
<title>Going deeper</title>
|
|
|
|
<para>The first section should (hopefully) have demonstrated the basics of
|
|
firstly defining advice, and secondly, of choosing where to apply that
|
|
advice using the notion of a pointcut. Of course, there is a great deal
|
|
more to Spring.NET AOP than the aforementioned single advice type and
|
|
pointcut. This section continues the exploration of Spring.NET AOP, and
|
|
describes the various advice and pointcuts that are available for you to
|
|
use (yes, there is more than one type of advice and pointcut).</para>
|
|
|
|
<sect2 xml:id="aop-quickstart-going-deeper-other-advice-types">
|
|
<title>Other types of Advice</title>
|
|
|
|
<para>The advice that was demonstrated and explained in the preceding
|
|
section is what is termed <emphasis>'around advice'</emphasis>. The name
|
|
<emphasis>'around advice'</emphasis> is used because the advice is
|
|
applied <emphasis>around</emphasis> the target method invocation. In the
|
|
specific case of the <literal>ConsoleLoggingAroundAdvice</literal>
|
|
advice that was defined previously, the target was made available to the
|
|
advice as an <literal>IMethodInvocation</literal> object... a call
|
|
was made to the <literal>Console</literal> class before the target
|
|
was invoked, and a call was made to the <literal>Console</literal>
|
|
class after the target method invocation was invoked. The advice
|
|
surrounded the target, one could even say that the advice was totally
|
|
'around' the target... hence the name, <emphasis>'around
|
|
advice'</emphasis>.</para>
|
|
|
|
<para><emphasis>'around advice'</emphasis> provides one with the
|
|
opportunity to do things both <emphasis role="bold">before</emphasis>
|
|
the target gets a chance to do anything, and <emphasis
|
|
role="bold">after</emphasis> the target has returned: one even gets a
|
|
chance to inspect (and possibly even totally change) the return
|
|
value.</para>
|
|
|
|
<para>Sometimes you don't need all that power though. If we stick with
|
|
the example of the <literal>ConsoleLoggingAroundAdvice</literal>
|
|
advice, what if one just wants to log the fact that a method was called?
|
|
In that case one doesn't need to do anything <emphasis>after</emphasis>
|
|
the target method invocation is to be invoked, nor do you need access to
|
|
the return value of the target method invocation. In fact, you only want
|
|
to do something <emphasis>before</emphasis> the target is to be invoked
|
|
(in this case, print out a message to the system
|
|
<literal>Console</literal> detailing the name of the method). In the
|
|
tradition of good programming that says one should use only what one
|
|
needs and no more, Spring.NET has another type of advice that one can
|
|
use... if one only wants to do something <emphasis>before</emphasis> the
|
|
target method invocation is invoked, why bother with having to manually
|
|
call the <literal>Proceed()</literal> method? The most expedient
|
|
solution simply is to use <emphasis>'before advice'</emphasis>.</para>
|
|
|
|
<sect3 xml:id="aop-quickstart-going-deeper-before-advice">
|
|
<title>Before advice</title>
|
|
|
|
<para><emphasis>'before advice'</emphasis> is just that... it is
|
|
advice that runs <emphasis>before</emphasis> the target method
|
|
invocation is invoked. One does not get access to the target method
|
|
invocation itself, and one cannot return a value... this is a good
|
|
thing, because it means that you cannot inadvertently forget to call
|
|
the <literal>Proceed()</literal> method on the target, and it also
|
|
means that you cannot inadvertently forget to return the return value
|
|
of the target method invocation. If you don't need to inspect or
|
|
change the return value, or even do anything after the successful
|
|
execution of the target method invocation, then <emphasis>'before
|
|
advice'</emphasis> is just what you need.</para>
|
|
|
|
<para><emphasis>'before advice'</emphasis> in Spring.NET is defined by
|
|
the <literal>IMethodBeforeAdvice</literal> interface in the
|
|
<literal>Spring.Aop</literal> namespace. Lets just dive in with an
|
|
example... we'll use the same scenario as before to keep things
|
|
simple. Let's define the <emphasis>'before advice'</emphasis>
|
|
implementation first.</para>
|
|
|
|
<programlisting language="csharp"> public class ConsoleLoggingBeforeAdvice : IMethodBeforeAdvice
|
|
{
|
|
public void Before(MethodInfo method, object[] args, object target)
|
|
{
|
|
Console.Out.WriteLine("Intercepted call to this method : " + method.Name);
|
|
Console.Out.WriteLine(" The target is : " + target);
|
|
Console.Out.WriteLine(" The arguments are : ");
|
|
if(args != null)
|
|
{
|
|
foreach (object arg in args)
|
|
{
|
|
Console.Out.WriteLine("\t: " + arg);
|
|
}
|
|
}
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Let's apply a single instance of the
|
|
<literal>ConsoleLoggingBeforeAdvice</literal> advice to the
|
|
invocation of the <literal>Execute()</literal> method of the
|
|
<literal>ServiceCommand</literal>. What follows is programmatic
|
|
configuration; as you can see, its pretty much identical to the
|
|
previous version... the only difference is that we're using our new
|
|
<emphasis>'before advice'</emphasis> (encapsulated as an instance of
|
|
the <literal>ConsoleLoggingBeforeAdvice</literal> class).</para>
|
|
|
|
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
|
|
factory.AddAdvice(new ConsoleLoggingBeforeAdvice());
|
|
ICommand command = (ICommand) factory.GetProxy();
|
|
command.Execute();</programlisting>
|
|
|
|
<para>The result of executing the above snippet of code will look
|
|
something like this...</para>
|
|
|
|
<programlisting> Intercepted call to this method : Execute
|
|
The target is : Spring.Examples.AopQuickStart.ServiceCommand
|
|
The arguments are :</programlisting>
|
|
|
|
<para>The output clearly indicates that the advice was applied
|
|
<emphasis role="bold">before</emphasis> the invocation of the advised
|
|
method. Notice that in contrast to <emphasis>'around
|
|
advice'</emphasis>, with <emphasis>'before advice'</emphasis> there is
|
|
no chance of forgetting to call the <literal>Proceed()</literal>
|
|
method on the target, because one does not have access to the
|
|
<literal>IMethodInvocation</literal> (as is the case with
|
|
<emphasis>'around advice'</emphasis>)... similarly, you cannot forget
|
|
to return the return value either.</para>
|
|
|
|
<para>If you can use <emphasis>'before advice'</emphasis>, then do so.
|
|
The simpler programming model offered by <emphasis>'before
|
|
advice'</emphasis> means that there is less to remember, and thus
|
|
potentially less things to get wrong.</para>
|
|
|
|
<para>Here is the Spring.NET XML configuration for applying our
|
|
<emphasis>'before advice'</emphasis> declaratively...</para>
|
|
|
|
<programlisting language="myxml"> <object id="beforeAdvice"
|
|
type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"/>
|
|
|
|
<object id="myServiceObject"
|
|
type="Spring.Aop.Framework.ProxyFactoryObject">
|
|
<property name="target">
|
|
<object id="myServiceObjectTarget"
|
|
type="Spring.Examples.AopQuickStart.ServiceCommand"/>
|
|
</property>
|
|
<property name="interceptorNames">
|
|
<list>
|
|
<value>beforeAdvice</value>
|
|
</list>
|
|
</property>
|
|
</object></programlisting>
|
|
</sect3>
|
|
|
|
<sect3 xml:id="aop-quickstart-going-deeper-after-advice">
|
|
<title>After advice</title>
|
|
|
|
<para>Just as <emphasis>'before advice'</emphasis> defines advice that
|
|
executes <emphasis role="bold">before</emphasis> an advised target,
|
|
<emphasis>'after advice'</emphasis> is advice that executes <emphasis
|
|
role="bold">after</emphasis> a target has been executed.</para>
|
|
|
|
<para><emphasis>'after advice'</emphasis> in Spring.NET is defined by
|
|
the <literal>IAfterReturningAdvice</literal> interface in the
|
|
<literal>Spring.Aop</literal> namespace. Again, lets just fire on
|
|
ahead with an example... again, we'll use the same scenario as before
|
|
to keep things simple.</para>
|
|
|
|
<programlisting language="csharp"> public class ConsoleLoggingAfterAdvice : IAfterReturningAdvice
|
|
{
|
|
public void AfterReturning(
|
|
object returnValue, MethodInfo method, object[] args, object target)
|
|
{
|
|
Console.Out.WriteLine("This method call returned successfully : " + method.Name);
|
|
Console.Out.WriteLine(" The target was : " + target);
|
|
Console.Out.WriteLine(" The arguments were : ");
|
|
if(args != null)
|
|
{
|
|
foreach (object arg in args)
|
|
{
|
|
Console.Out.WriteLine("\t: " + arg);
|
|
}
|
|
}
|
|
Console.Out.WriteLine(" The return value is : " + returnValue);
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Let's apply a single instance of the
|
|
<literal>ConsoleLoggingAfterAdvice</literal> advice to the
|
|
invocation of the <literal>Execute()</literal> method of the
|
|
<literal>ServiceCommand</literal>. What follows is programmatic
|
|
configuration; as you can, its pretty much identical to the
|
|
<emphasis>'before advice'</emphasis> version (which in turn was pretty
|
|
much identical to the original <emphasis>'around advice'</emphasis>
|
|
version)... the only real difference is that we're using our new
|
|
<emphasis>'after advice'</emphasis> (encapsulated as an instance of
|
|
the <literal>ConsoleLoggingAfterAdvice</literal> class).</para>
|
|
|
|
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
|
|
factory.AddAdvice(new ConsoleLoggingAfterAdvice());
|
|
ICommand command = (ICommand) factory.GetProxy();
|
|
command.Execute();</programlisting>
|
|
|
|
<para>The result of executing the above snippet of code will look
|
|
something like this...</para>
|
|
|
|
<programlisting> This method call returned successfully : Execute
|
|
The target was : Spring.Examples.AopQuickStart.ServiceCommand
|
|
The arguments were :
|
|
The return value is : null</programlisting>
|
|
|
|
<para>The output clearly indicates that the advice was applied
|
|
<emphasis role="bold">after</emphasis> the invocation of the advised
|
|
method. Again, it bears repeating that your real world development
|
|
will actually have an advice implementation that does something useful
|
|
after the invocation of an advised method. Notice that in contrast to
|
|
<emphasis>'around advice'</emphasis>, with <emphasis>'after
|
|
advice'</emphasis> there is no chance of forgetting to call the
|
|
<literal>Proceed()</literal> method on the target, because just like
|
|
<emphasis>'before advice'</emphasis> you don't have access to the
|
|
<literal>IMethodInvocation</literal>... similarly, although you
|
|
get access to the return value of the target, you cannot forget to
|
|
return the return value either. You can however change the state of
|
|
the return value, typically by setting some of its properties, or by
|
|
calling methods on it.</para>
|
|
|
|
<para>The best-practice rule for <emphasis>'after advice'</emphasis>
|
|
is much the same as it is for <emphasis>'before advice'</emphasis>;
|
|
namely that if you can use <emphasis>'after advice'</emphasis>, then
|
|
do so (in preference to using <emphasis>'around advice'</emphasis>).
|
|
The simpler programming model offered by <emphasis>'after
|
|
advice'</emphasis> means that there is less to remember, and thus less
|
|
things to get potentially wrong.</para>
|
|
|
|
<para>A possible use case for <emphasis>'after advice'</emphasis>
|
|
would include performing access control checks on the return value of
|
|
an advised method invocation; consider the case of a service that
|
|
returns a list of document URI's... depending on the identity of the
|
|
(Windows) user that is running the program that is calling this
|
|
service, one could strip out those URI's that contain sensitive data
|
|
for which the user does not have sufficient privileges to access. That
|
|
is just one (real world) scenario... I'm sure you can think of plenty
|
|
more that are a whole lot more relevant to your own development
|
|
needs.</para>
|
|
|
|
<para>Here is the Spring.NET XML configuration for applying the
|
|
<emphasis>'after advice'</emphasis> declaratively...</para>
|
|
|
|
<programlisting language="myxml"> <object id="afterAdvice"
|
|
type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"/>
|
|
|
|
<object id="myServiceObject"
|
|
type="Spring.Aop.Framework.ProxyFactoryObject">
|
|
<property name="target">
|
|
<object id="myServiceObjectTarget"
|
|
type="Spring.Examples.AopQuickStart.ServiceCommand"/>
|
|
</property>
|
|
<property name="interceptorNames">
|
|
<list>
|
|
<value>afterAdvice</value>
|
|
</list>
|
|
</property>
|
|
</object></programlisting>
|
|
</sect3>
|
|
|
|
<sect3 xml:id="aop-quickstart-going-deeper-throws-advice">
|
|
<title>Throws advice</title>
|
|
|
|
<para>So far we've covered <emphasis>'around advice'</emphasis>,
|
|
<emphasis>'before advice'</emphasis>, and <emphasis>'after
|
|
advice'</emphasis>... these advice types will see you through most if
|
|
not all of your AOP needs. However, one of the remaining advice types
|
|
that Spring.NET has in its locker is <emphasis>'throws
|
|
advice'</emphasis>.</para>
|
|
|
|
<para><emphasis>'throws advice'</emphasis> is advice that executes
|
|
when an advised method invocation <emphasis>throws</emphasis> an
|
|
exception.. hence the name. One basically applies the
|
|
<emphasis>'throws advice'</emphasis> to a target object in much the
|
|
same way as any of the previously mentioned advice types. If during
|
|
the execution of ones application none of any of the advised methods
|
|
throws an exception, then the <emphasis>'throws advice'</emphasis>
|
|
will never execute. However, if during the execution of your
|
|
application an advised method <emphasis>does</emphasis> throw an
|
|
exception, then the <emphasis>'throws advice'</emphasis> will kick in
|
|
and be executed. You can use <emphasis>'throws advice'</emphasis> to
|
|
apply a common exception handling policy across the various objects in
|
|
your application, or to perform logging of every exception thown by an
|
|
advised method, or to alert (perhaps via email) the support team in
|
|
the case of particularly of critical exceptions... the list of
|
|
possible uses cases is of course endless.</para>
|
|
|
|
<para>The <emphasis>'throws advice'</emphasis> type in Spring.NET is
|
|
defined by the <literal>IThrowsAdvice</literal> interface in the
|
|
<literal>Spring.Aop</literal> namespace... basically, one defines on
|
|
one's <emphasis>'throws advice'</emphasis> implementation class what
|
|
types of exception are going to be handled. Lets take a quick look at
|
|
the <literal>IThrowsAdvice</literal> interface...</para>
|
|
|
|
<programlisting language="csharp"> public interface IThrowsAdvice : IAdvice
|
|
{
|
|
}</programlisting>
|
|
|
|
<para>Yes, that is really it... it is a marker interface that has no
|
|
methods on it. You may be wondering how Spring.NET determines which
|
|
methods to call to effect the running of one's <emphasis>'throws
|
|
advice'</emphasis>. An example would perhaps be illustrative at this
|
|
point, so here is some simple Spring.NET style <emphasis>'throws
|
|
advice'</emphasis>...</para>
|
|
|
|
<programlisting language="csharp"> public class ConsoleLoggingThrowsAdvice : IThrowsAdvice
|
|
{
|
|
public void AfterThrowing(Exception ex)
|
|
{
|
|
Console.Out.WriteLine("Advised method threw this exception : " + ex);
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Lets also change the implementation of the
|
|
<literal>Execute()</literal> method of the
|
|
<literal>ServiceCommand</literal> class such that it throws an
|
|
exception. This will allow the advice encapsulated by the above
|
|
<literal>ConsoleLoggingThrowsAdvice</literal> to kick in.</para>
|
|
|
|
<programlisting language="csharp"> public class ServiceCommand : ICommand
|
|
{
|
|
public void Execute()
|
|
{
|
|
throw new UnauthorizedAccessException();
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Let's programmatically apply the <emphasis>'throws
|
|
advice'</emphasis> (an instance of our
|
|
<literal>ConsoleLoggingThrowsAdvice</literal>) to the invocation
|
|
of the <literal>Execute()</literal> method of the above
|
|
<literal>ServiceCommand</literal> class; to wit...</para>
|
|
|
|
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
|
|
factory.AddAdvice(new ConsoleLoggingThrowsAdvice());
|
|
ICommand command = (ICommand) factory.GetProxy();
|
|
command.Execute();</programlisting>
|
|
|
|
<para>The result of executing the above snippet of code will look
|
|
something like this...</para>
|
|
|
|
<programlisting> Advised method threw this exception : System.UnauthorizedAccessException:
|
|
Attempted to perform an unauthorized operation.</programlisting>
|
|
|
|
<para>As can be seen from the output, the
|
|
<literal>ConsoleLoggingThrowsAdvice</literal> kicked in when the
|
|
advised method invocation threw an exception. There are a number of
|
|
things to note about the
|
|
<literal>ConsoleLoggingThrowsAdvice</literal> advice class, so
|
|
lets take them each in turn.</para>
|
|
|
|
<para>In Spring.NET, <emphasis>'throws advice'</emphasis> means that
|
|
you have to define a class that implements the
|
|
<literal>IThrowsAdvice</literal> interface. Then, for each type of
|
|
exception that your <emphasis>'throws advice'</emphasis> is going to
|
|
handle, you have to define a method with this signature...</para>
|
|
|
|
<programlisting language="csharp"> void AfterThrowing(Exception ex)</programlisting>
|
|
|
|
<para>Basically, your exception handling method has to be named
|
|
<literal>AfterThrowing</literal>. This name is important... your
|
|
exception handling method(s) absolutely must be called
|
|
<literal>AfterThrowing</literal>. If your handler method is not called
|
|
<literal>AfterThrowing</literal>, then your <emphasis>'throws
|
|
advice'</emphasis> will <emphasis role="bold">never</emphasis> be
|
|
called, it's as simple as that. Currently, this naming restriction is
|
|
not configurable (although it may well be opened up for configuration
|
|
in the future).</para>
|
|
|
|
<para>Your exception handling method must (at the very least) declare
|
|
a parameter that is an <literal>Exception</literal> type... this
|
|
parameter can be the root <literal>Exception</literal> class (as
|
|
in the case of the above example), or it can be an
|
|
<literal>Exception</literal> subclass if you only want to handle
|
|
certain types of exception. It is good practice to always make your
|
|
exception handling methods have an <literal>Exception</literal>
|
|
parameter that is the most specialized
|
|
<literal>Exception</literal> type possible... i.e. if you are
|
|
applying <emphasis>'throws advice'</emphasis> to a method that could
|
|
only ever throw <literal>ArgumentException</literal>s, then
|
|
declare the parameter of your exception handling method as...</para>
|
|
|
|
<programlisting language="csharp"> void AfterThrowing(ArgumentException ex)</programlisting>
|
|
|
|
<para>Note that your exception handling method can have any return
|
|
type, but returning any value from a Spring.NET <emphasis>'throws
|
|
advice'</emphasis> method would be a waste of time... the Spring.NET
|
|
AOP infrastructure will simply ignore the return value, so always
|
|
define the return type of your exception handling methods to be
|
|
<literal>void</literal>.</para>
|
|
|
|
<para>Finally, here is the Spring.NET XML configuration for applying
|
|
the <emphasis>'throws advice'</emphasis> declaratively...</para>
|
|
|
|
<programlisting language="myxml"> <object id="throwsAdvice"
|
|
type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"/>
|
|
|
|
<object id="myServiceObject"
|
|
type="Spring.Aop.Framework.ProxyFactoryObject">
|
|
<property name="target">
|
|
<object id="myServiceObjectTarget"
|
|
type="Spring.Examples.AopQuickStart.ServiceCommand"/>
|
|
</property>
|
|
<property name="interceptorNames">
|
|
<list>
|
|
<value>throwsAdvice</value>
|
|
</list>
|
|
</property>
|
|
</object></programlisting>
|
|
|
|
<para>One thing that cannot be done using <emphasis>'throws
|
|
advice'</emphasis> is exception swallowing. It is not possible to
|
|
define an exception handling method in a <emphasis>'throws
|
|
advice'</emphasis> implementation that will swallow any exception and
|
|
prevent said exception from bubbling up the call stack. The nearest
|
|
thing that one can do is define an exception handling method in a
|
|
<emphasis>'throws advice'</emphasis> implementation that will wrap the
|
|
handled exception in another exception; one would then throw the
|
|
wrapped exception in the body of one's exception handling method. One
|
|
can use this to implement some sort of exception translation or
|
|
exception scrubbing policy, in which implementation specific
|
|
exceptions (such as <literal>SqlException</literal> or
|
|
<literal>OracleException</literal> exceptions being thrown by an
|
|
advised data access object) get replaced with a business exception
|
|
that has meaning to the service objects in one's business layer. A toy
|
|
example of this type of <emphasis>'throws advice'</emphasis> can be
|
|
seen below.</para>
|
|
|
|
<programlisting language="csharp"> public class DataAccessExceptionScrubbingThrowsAdvice : IThrowsAdvice
|
|
{
|
|
public void AfterThrowing (SqlException ex)
|
|
{
|
|
// business objects in higher level service layer need only deal with PersistenceException...
|
|
throw new PersistenceException ("Cannot access persistent storage.", ex.StackTrace);
|
|
}
|
|
}</programlisting>
|
|
|
|
<para><emphasis> Spring.NET's data access library already has this
|
|
kind of functionality (and is a whole lot more sophisticated)... the
|
|
above example is merely being used for illustrative purposes.
|
|
</emphasis></para>
|
|
|
|
<para>This treatment of <emphasis>'throws advice'</emphasis>, and of
|
|
Spring.NET's implementation of it is rather simplistic.
|
|
<emphasis>'throws advice'</emphasis> features that have been omitted
|
|
include the fact that one can define exception handling methods that
|
|
permit access to the original object, method, and method arguments of
|
|
the advised method invocation that threw the original exception. This
|
|
is a quickstart guide though, and is not meant to be exhaustive... do
|
|
consult the <emphasis>'throws advice'</emphasis> section of the
|
|
reference documentation, which describes how to declare an exception
|
|
handling method that gives one access to the above extra objects, and
|
|
how to declare multiple exception handling methods on the same
|
|
<literal>IThrowsAdvice</literal> implementation class (see <xref
|
|
linkend="aop-introduction-advice-types-throws" />).</para>
|
|
</sect3>
|
|
|
|
<sect3 xml:id="aop-quickstart-going-deeper-introduction-advice">
|
|
<title>Introductions (mixins)</title>
|
|
|
|
<para>In a nutshell, introductions are all about adding new state and
|
|
behaviour to arbitrary objects... transparently and at runtime.
|
|
Introductions (also called mixins) allow one to emulate multiple
|
|
inheritance, typically with an eye towards applying crosscutting state
|
|
and operations to a wide swathe of objects in your application that
|
|
don't share the same inheritance hierarchy.</para>
|
|
</sect3>
|
|
|
|
<sect3 xml:id="aop-quickstart-going-deeper-layering-advice">
|
|
<title>Layering advice</title>
|
|
|
|
<para>The examples shown so far have all demonstrated the application
|
|
of a single advice instance to an advised object. Spring.NET's flavor
|
|
of AOP would be pretty poor if one could only apply a single advice
|
|
instance per advised object... it is perfectly valid to apply multiple
|
|
advice to an advised object. For example, one might apply
|
|
transactional advice to a service object, and also apply a security
|
|
access checking advice to that same advised service object.</para>
|
|
|
|
<para>In the interests of keeping this section lean and tight, let's
|
|
simply apply <emphasis>all</emphasis> of the advice types that have
|
|
been previously described to a single advised object... in this first
|
|
instance we'll just use the default pointcut which means that every
|
|
possible joinpoint will be advised, and you'll be able to see that the
|
|
various advice instances are applied in order.</para>
|
|
|
|
<para>Please do consult the class definitions for the following
|
|
previously defined advice types to see exactly what each advice type
|
|
implementation does... we're going to be using single instances of the
|
|
<literal>ConsoleLoggingAroundAdvice</literal>,
|
|
<literal>ConsoleLoggingBeforeAdvice</literal>,
|
|
<literal>ConsoleLoggingAfterAdvice</literal>, and
|
|
<literal>ConsoleLoggingThrowsAdvice</literal> advice to advise a
|
|
single instance of the <literal>ServiceCommand</literal>
|
|
class.</para>
|
|
|
|
<para>You can find the following listing and executable application in
|
|
the AopQuickStart solution in the project
|
|
<literal>Spring.AopQuickStart.Step1</literal>.</para>
|
|
|
|
<programlisting language="csharp"> ProxyFactory factory = new ProxyFactory(new ServiceCommand());
|
|
factory.AddAdvice(new ConsoleLoggingBeforeAdvice());
|
|
factory.AddAdvice(new ConsoleLoggingAfterAdvice());
|
|
factory.AddAdvice(new ConsoleLoggingThrowsAdvice());
|
|
factory.AddAdvice(new ConsoleLoggingAroundAdvice());
|
|
ICommand command = (ICommand) factory.GetProxy();
|
|
command.Execute();</programlisting>
|
|
|
|
<para>Here is the Spring.NET XML configuration for declaratively
|
|
applying multiple advice.</para>
|
|
|
|
<para>You can find the following listing and executable application in
|
|
the AopQuickStart solution in the project
|
|
<literal>Spring.AopQuickStart.Step2</literal>.</para>
|
|
|
|
<programlisting language="myxml"> <object id="throwsAdvice"
|
|
type="Spring.Examples.AopQuickStart.ConsoleLoggingThrowsAdvice"/>
|
|
<object id="afterAdvice"
|
|
type="Spring.Examples.AopQuickStart.ConsoleLoggingAfterAdvice"/>
|
|
<object id="beforeAdvice"
|
|
type="Spring.Examples.AopQuickStart.ConsoleLoggingBeforeAdvice"/>
|
|
<object id="aroundAdvice"
|
|
type="Spring.Examples.AopQuickStart.ConsoleLoggingAroundAdvice"/>
|
|
|
|
<object id="myServiceObject"
|
|
type="Spring.Aop.Framework.ProxyFactoryObject">
|
|
<property name="target">
|
|
<object id="myServiceObjectTarget"
|
|
type="Spring.Examples.AopQuickStart.ServiceCommand"/>
|
|
</property>
|
|
<property name="interceptorNames">
|
|
<list>
|
|
<value>throwsAdvice</value>
|
|
<value>afterAdvice</value>
|
|
<value>beforeAdvice</value>
|
|
<value>aroundAdvice</value>
|
|
</list>
|
|
</property>
|
|
</object></programlisting>
|
|
</sect3>
|
|
|
|
<sect3 xml:id="aop-quickstart-going-deeper-configuring-advice">
|
|
<title>Configuring advice</title>
|
|
|
|
<para>In case it is not immediately apparent, remember that advice is
|
|
just a plain old .NET object (a PONO); advice can have constructors
|
|
that can take any number of parameters, and like any other .NET class,
|
|
advice can have properties. What this means is that one can leverage
|
|
the power of the Spring.NET IoC container to apply the IoC principle
|
|
to one's advice, and in so doing reap all the benefits of Dependency
|
|
Injection.</para>
|
|
|
|
<para>Consider the case of throws advice that needs to report (fatal)
|
|
exceptions to a first line support centre. The throws advice could
|
|
declare a dependency on a reporting service via a .NET property, and
|
|
the Spring.NET container could dependency inject the reporting service
|
|
dependency into the throws advice when it is being created; the
|
|
reporting dependency might be a simple Log4NET wrapper, or a Windows
|
|
EventLog wrapper, or a custom reporting exception reporting service
|
|
that sends detailed emails concerning the fatal exception.</para>
|
|
|
|
<para>Also bear in mind the fact that Spring.NET's AOP implementation
|
|
is quite independent of Spring.NET's IoC container. As you have seen,
|
|
the various examples used in this have illustrated both programmatic
|
|
and declarative AOP configuration (the latter being illustrated via
|
|
Spring.NET's IoC XML configuration mechanism).</para>
|
|
</sect3>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="aop-quickstart-going-deeper-attribute-pointcuts">
|
|
<title>Using Attributes to define Pointcuts</title>
|
|
|
|
<para></para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="aop-quickstart-cookbook">
|
|
<title>The Spring.NET AOP Cookbook</title>
|
|
|
|
<para>The preceding treatment of Spring.NET AOP has (quite intentionally)
|
|
been decidedly simple. The overarching aim was to convey the concepts of
|
|
Spring.NET AOP... this section of the Spring.NET AOP guide contains a
|
|
number of real world examples of the application of Spring.NET AOP.</para>
|
|
|
|
<sect2 xml:id="aop-quickstart-cookbook-caching">
|
|
<title>Caching</title>
|
|
|
|
<para>This example illustrates one of the more common usages of AOP...
|
|
caching.</para>
|
|
|
|
<para>Lets consider the scenario where we have some static reference
|
|
data that needs to be kept around for the duration of an application.
|
|
The data will almost never change over the uptime of an application, and
|
|
it exists only in the database to satisfy referential integrity amongst
|
|
the various relations in the database schema. An example of such static
|
|
(and typically immutable) reference data would be a collection of
|
|
<literal>Country</literal> objects (comprising a country name and a
|
|
code). What we would like to do is suck in the collection of
|
|
<literal>Country</literal> objects and then pin them in a cache.
|
|
This saves us having to hit the back end database again and again every
|
|
time we need to reference a country in our application (for example, to
|
|
populate dropdown controls in a Windows Forms desktop
|
|
application).</para>
|
|
|
|
<para>The Data Access Object (DAO) that will load the collection of
|
|
<literal>Country</literal> objects is called
|
|
<literal>AdoCountryDao</literal> (it is an implementation of the
|
|
data-access-technology agnostic DAO interface called
|
|
<literal>ICountryDao</literal>). The implementation of the
|
|
<literal>AdoCountryDao</literal> is quite simple, in that every time
|
|
the <literal>FindAllCountries</literal> instance method is called, an
|
|
instance will query the database for an
|
|
<literal>IDataReader</literal> and hydrate zero or more
|
|
<literal>Country</literal> objects using the returned data.</para>
|
|
|
|
<programlisting language="csharp"> public class AdoCountryDao : ICountryDao
|
|
{
|
|
public IList FindAllCountries ()
|
|
{
|
|
// implementation elided for clarity...
|
|
return countries;
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Ideally, what we would like to have happen is for the results of
|
|
the <emphasis>first</emphasis> call to the
|
|
<literal>FindAllCountries</literal> instance method to be cached. We
|
|
would also like to do this in a non-invasive way, because caching is
|
|
something that we might want to apply at any number of points across the
|
|
codebase of our application. So, to address what we have identified as a
|
|
<emphasis>cross cutting concern</emphasis>, we can use Spring.NET AOP to
|
|
implement the caching.</para>
|
|
|
|
<para>The mechanism that this example is going to use to identify (or
|
|
pick out) areas in our application that we would like to apply caching
|
|
to is a .NET <literal>Attribute</literal>. Spring.NET ships with a
|
|
number of useful custom .NET <literal>Attribute</literal>
|
|
implementations, one of which is the cunningly named
|
|
<literal>CacheAttribute</literal>. In the specific case of this
|
|
example, we are simply going to decorate the definition of the
|
|
<literal>FindAllCountries</literal> instance method with the
|
|
<literal>CacheAttribute</literal>.</para>
|
|
|
|
<programlisting language="csharp"> public class AdoCountryDao : ICountryDao
|
|
{
|
|
[Cache]
|
|
public IList FindAllCountries ()
|
|
{
|
|
// implementation elided for clarity...
|
|
return countries;
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>The SpringAir reference application that is packaged as part of
|
|
the Spring.NET distribution comes with a working example of caching
|
|
applied using Spring.NET AOP (see <xref linkend="springair" />).</para>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="aop-quickstart-cookbook-performance-monitoring-windows">
|
|
<title>Performance Monitoring</title>
|
|
|
|
<para>This recipe show how easy it is to instrument the classes and
|
|
objects in an application for performance monitoring. The performance
|
|
monitoring implementation uses one of the (many) Windows performance
|
|
counters to display and track the performance data.</para>
|
|
</sect2>
|
|
|
|
<sect2 xml:id="aop-quickstart-cookbook-retry">
|
|
<title>Retry Rules</title>
|
|
|
|
<para>This final recipe describes a simple (but really quite useful)
|
|
aspect... retry logic. Using Spring.NET AOP, it is quite easy to
|
|
surround an operation such as a method that opens a connection to a
|
|
database with a (configurable) aspect that tries to obtain a database
|
|
connection any number of times in the event of a failure.</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="aop-quickstart-best-practices">
|
|
<title>Spring.NET AOP Best Practices</title>
|
|
|
|
<para>Spring.NET AOP is an 80% AOP solution, in that it only tries to
|
|
solve the 80% of those cases where AOP is a good fit in a typical
|
|
enterprise application. This final section of the Spring.NET AOP guide
|
|
describes where Spring.NET AOP is typically useful (the 80%), as well as
|
|
where Spring.NET AOP is not a good fit (the 20%).</para>
|
|
</sect1>
|
|
</chapter> |