3665 lines
168 KiB
XML
3665 lines
168 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
|
|
|
|
<chapter id="aop">
|
|
<title>Aspect Oriented Programming with Spring</title>
|
|
|
|
<section id="aop-introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para><emphasis>Aspect-Oriented Programming</emphasis> (AOP) complements
|
|
Object-Oriented Programming (OOP) by providing another way of thinking
|
|
about program structure. The key unit of modularity in OOP is the class,
|
|
whereas in AOP the unit of modularity is the <emphasis>aspect</emphasis>.
|
|
Aspects enable the modularization of concerns such as transaction
|
|
management that cut across multiple types and objects. (Such concerns are
|
|
often termed <emphasis>crosscutting</emphasis> concerns in AOP
|
|
literature.)</para>
|
|
|
|
<para>One of the key components of Spring is the <emphasis>AOP
|
|
framework</emphasis>. While the Spring IoC container does not depend on
|
|
AOP, meaning you do not need to use AOP if you don't want to, AOP
|
|
complements Spring IoC to provide a very capable middleware
|
|
solution.</para>
|
|
|
|
<sidebar>
|
|
<title>Spring 2.0 AOP</title>
|
|
|
|
<para>Spring 2.0 introduces a simpler and more powerful way of writing
|
|
custom aspects using either a <link linkend="aop-schema">schema-based
|
|
approach</link> or the <link linkend="aop-ataspectj">@AspectJ annotation
|
|
style</link>. Both of these styles offer fully typed advice and use of
|
|
the AspectJ pointcut language, while still using Spring AOP for
|
|
weaving.</para>
|
|
|
|
<para>The Spring 2.0 schema- and @AspectJ-based AOP support is discussed
|
|
in this chapter. Spring 2.0 AOP remains fully backwards compatible with
|
|
Spring 1.2 AOP, and the lower-level AOP support offered by the Spring
|
|
1.2 APIs is discussed in <link linkend="aop-api">the following
|
|
chapter</link>.</para>
|
|
</sidebar>
|
|
|
|
<para>AOP is used in the Spring Framework to...</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>... provide declarative enterprise services, especially as a
|
|
replacement for EJB declarative services. The most important such
|
|
service is <link
|
|
linkend="transaction-declarative"><emphasis>declarative transaction
|
|
management</emphasis></link>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>... allow users to implement custom aspects, complementing their
|
|
use of OOP with AOP.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<remark><para>If you are interested only in generic declarative services
|
|
or other pre-packaged declarative middleware services such as pooling, you
|
|
do not need to work directly with Spring AOP, and can skip most of this
|
|
chapter. </para></remark>
|
|
|
|
<section id="aop-introduction-defn">
|
|
<title>AOP concepts</title>
|
|
|
|
<para>Let us begin by defining some central AOP concepts and
|
|
terminology. These terms are not Spring-specific... unfortunately, AOP
|
|
terminology is not particularly intuitive; however, it would be even
|
|
more confusing if Spring used its own terminology.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><emphasis>Aspect</emphasis>: a modularization of a concern
|
|
that cuts across multiple classes. Transaction management is a good
|
|
example of a crosscutting concern in J2EE applications. In Spring
|
|
AOP, aspects are implemented using regular classes (the <link
|
|
linkend="aop-schema">schema-based approach</link>) or regular
|
|
classes annotated with the <interfacename>@Aspect</interfacename>
|
|
annotation (the <link
|
|
linkend="aop-ataspectj"><interfacename>@AspectJ</interfacename>
|
|
style</link>).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Join point</emphasis>: a point during the execution
|
|
of a program, such as the execution of a method or the handling of
|
|
an exception. In Spring AOP, a join point
|
|
<emphasis>always</emphasis> represents a method execution.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Advice</emphasis>: action taken by an aspect at a
|
|
particular join point. Different types of advice include "around,"
|
|
"before" and "after" advice. (Advice types are discussed below.)
|
|
Many AOP frameworks, including Spring, model an advice as an
|
|
<emphasis>interceptor</emphasis>, maintaining a chain of
|
|
interceptors <emphasis>around</emphasis> the join point.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Pointcut</emphasis>: a predicate that matches join
|
|
points. Advice is associated with a pointcut expression and runs at
|
|
any join point matched by the pointcut (for example, the execution
|
|
of a method with a certain name). The concept of join points as
|
|
matched by pointcut expressions is central to AOP, and Spring uses
|
|
the AspectJ pointcut expression language by default.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Introduction</emphasis>: declaring additional
|
|
methods or fields on behalf of a type. Spring AOP allows you to
|
|
introduce new interfaces (and a corresponding implementation) to any
|
|
advised object. For example, you could use an introduction to make a
|
|
bean implement an <interfacename>IsModified</interfacename>
|
|
interface, to simplify caching. (An introduction is known as an
|
|
inter-type declaration in the AspectJ community.)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Target object</emphasis>: object being advised by
|
|
one or more aspects. Also referred to as the
|
|
<emphasis>advised</emphasis> object. Since Spring AOP is implemented
|
|
using runtime proxies, this object will always be a
|
|
<emphasis>proxied</emphasis> object.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>AOP proxy</emphasis>: an object created by the AOP
|
|
framework in order to implement the aspect contracts (advise method
|
|
executions and so on). In the Spring Framework, an AOP proxy will be
|
|
a JDK dynamic proxy or a CGLIB proxy.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Weaving</emphasis>: linking aspects with other
|
|
application types or objects to create an advised object. This can
|
|
be done at compile time (using the AspectJ compiler, for example),
|
|
load time, or at runtime. Spring AOP, like other pure Java AOP
|
|
frameworks, performs weaving at runtime.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Types of advice:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><emphasis>Before advice</emphasis>: Advice that executes
|
|
before a join point, but which does not have the ability to prevent
|
|
execution flow proceeding to the join point (unless it throws an
|
|
exception).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>After returning advice</emphasis>: Advice to be
|
|
executed after a join point completes normally: for example, if a
|
|
method returns without throwing an exception.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>After throwing advice</emphasis>: Advice to be
|
|
executed if a method exits by throwing an exception.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>After (finally) advice</emphasis>: Advice to be
|
|
executed regardless of the means by which a join point exits (normal
|
|
or exceptional return).</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>Around advice</emphasis>: Advice that surrounds a
|
|
join point such as a method invocation. This is the most powerful
|
|
kind of advice. Around advice can perform custom behavior before and
|
|
after the method invocation. It is also responsible for choosing
|
|
whether to proceed to the join point or to shortcut the advised
|
|
method execution by returning its own return value or throwing an
|
|
exception.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Around advice is the most general kind of advice. Since Spring
|
|
AOP, like AspectJ, provides a full range of advice types, we recommend
|
|
that you use the least powerful advice type that can implement the
|
|
required behavior. For example, if you need only to update a cache with
|
|
the return value of a method, you are better off implementing an after
|
|
returning advice than an around advice, although an around advice can
|
|
accomplish the same thing. Using the most specific advice type provides
|
|
a simpler programming model with less potential for errors. For example,
|
|
you do not need to invoke the <methodname>proceed()</methodname> method
|
|
on the <interfacename>JoinPoint</interfacename> used for around advice,
|
|
and hence cannot fail to invoke it.</para>
|
|
|
|
<para>In Spring 2.0, all advice parameters are statically typed, so that
|
|
you work with advice parameters of the appropriate type (the type of the
|
|
return value from a method execution for example) rather than
|
|
<classname>Object</classname> arrays.</para>
|
|
|
|
<para>The concept of join points, matched by pointcuts, is the key to
|
|
AOP which distinguishes it from older technologies offering only
|
|
interception. Pointcuts enable advice to be targeted independently of
|
|
the Object-Oriented hierarchy. For example, an around advice providing
|
|
declarative transaction management can be applied to a set of methods
|
|
spanning multiple objects (such as all business operations in the
|
|
service layer).</para>
|
|
</section>
|
|
|
|
<section id="aop-introduction-spring-defn">
|
|
<title>Spring AOP capabilities and goals</title>
|
|
|
|
<para>Spring AOP is implemented in pure Java. There is no need for a
|
|
special compilation process. Spring AOP does not need to control the
|
|
class loader hierarchy, and is thus suitable for use in a J2EE web
|
|
container or application server.</para>
|
|
|
|
<para>Spring AOP currently supports only method execution join points
|
|
(advising the execution of methods on Spring beans). Field interception
|
|
is not implemented, although support for field interception could be
|
|
added without breaking the core Spring AOP APIs. If you need to advise
|
|
field access and update join points, consider a language such as
|
|
AspectJ.</para>
|
|
|
|
<para>Spring AOP's approach to AOP differs from that of most other AOP
|
|
frameworks. The aim is not to provide the most complete AOP
|
|
implementation (although Spring AOP is quite capable); it is rather to
|
|
provide a close integration between AOP implementation and Spring IoC to
|
|
help solve common problems in enterprise applications.</para>
|
|
|
|
<para>Thus, for example, the Spring Framework's AOP functionality is
|
|
normally used in conjunction with the Spring IoC container. Aspects are
|
|
configured using normal bean definition syntax (although this allows
|
|
powerful "autoproxying" capabilities): this is a crucial difference from
|
|
other AOP implementations. There are some things you cannot do easily or
|
|
efficiently with Spring AOP, such as advise very fine-grained objects
|
|
(such as domain objects typically): AspectJ is the best choice in such
|
|
cases. However, our experience is that Spring AOP provides an excellent
|
|
solution to most problems in J2EE applications that are amenable to
|
|
AOP.</para>
|
|
|
|
<para>Spring AOP will never strive to compete with AspectJ to provide a
|
|
comprehensive AOP solution. We believe that both proxy-based frameworks
|
|
like Spring AOP and full-blown frameworks such as AspectJ are valuable,
|
|
and that they are complementary, rather than in competition. Spring 2.0
|
|
seamlessly integrates Spring AOP and IoC with AspectJ, to enable all
|
|
uses of AOP to be catered for within a consistent Spring-based
|
|
application architecture. This integration does not affect the Spring
|
|
AOP API or the AOP Alliance API: Spring AOP remains backward-compatible.
|
|
See <link linkend="aop-api">the following chapter</link> for a
|
|
discussion of the Spring AOP APIs.</para>
|
|
|
|
<note>
|
|
<para>One of the central tenets of the Spring Framework is that of
|
|
<emphasis>non-invasiveness</emphasis>; this is the idea that you
|
|
should not be forced to introduce framework-specific classes and
|
|
interfaces into your business/domain model. However, in some places
|
|
the Spring Framework does give you the option to introduce Spring
|
|
Framework-specific dependencies into your codebase: the rationale in
|
|
giving you such options is because in certain scenarios it might be
|
|
just plain easier to read or code some specific piece of functionality
|
|
in such a way. The Spring Framework (almost) always offers you the
|
|
choice though: you have the freedom to make an informed decision as to
|
|
which option best suits your particular use case or scenario.</para>
|
|
|
|
<para>One such choice that is relevant to this chapter is that of
|
|
which AOP framework (and which AOP style) to choose. You have the
|
|
choice of AspectJ and/or Spring AOP, and you also have the choice of
|
|
either the @AspectJ annotation-style approach or the Spring XML
|
|
configuration-style approach. The fact that this chapter chooses to
|
|
introduce the @AspectJ-style approach first should not be taken as an
|
|
indication that the Spring team favors the @AspectJ annotation-style
|
|
approach over the Spring XML configuration-style.</para>
|
|
|
|
<para>See the section entitled <xref linkend="aop-choosing" /> for a
|
|
fuller discussion of the whys and wherefores of each style.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="aop-introduction-proxies">
|
|
<title>AOP Proxies</title>
|
|
|
|
<para>Spring AOP defaults to using standard J2SE <emphasis>dynamic
|
|
proxies</emphasis> for AOP proxies. This enables any interface (or set
|
|
of interfaces) to be proxied.</para>
|
|
|
|
<para>Spring AOP can also use CGLIB proxies. This is necessary to proxy
|
|
classes, rather than interfaces. CGLIB is used by default if a business
|
|
object does not implement an interface. As it is good practice to
|
|
program to interfaces rather than classes, business classes normally
|
|
will implement one or more business interfaces. It is possible to <link
|
|
linkend="aop-autoproxy-force-CGLIB">force the use of CGLIB</link>, in
|
|
those (hopefully rare) cases where you need to advise a method that is
|
|
not declared on an interface, or where you need to pass a proxied object
|
|
to a method as a concrete type.</para>
|
|
|
|
<para>It is important to grasp the fact that Spring AOP is
|
|
<emphasis>proxy-based</emphasis>. See the section entitled <xref
|
|
linkend="aop-understanding-aop-proxies" /> for a thorough examination of
|
|
exactly what this implementation detail actually means.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="aop-ataspectj">
|
|
<title>@AspectJ support</title>
|
|
|
|
<para>@AspectJ refers to a style of declaring aspects as regular Java
|
|
classes annotated with Java 5 annotations. The @AspectJ style was
|
|
introduced by the <ulink url="http://www.eclipse.org/aspectj">AspectJ
|
|
project</ulink> as part of the AspectJ 5 release. Spring 2.0 interprets
|
|
the same annotations as AspectJ 5, using a library supplied by AspectJ for
|
|
pointcut parsing and matching. The AOP runtime is still pure Spring AOP
|
|
though, and there is no dependency on the AspectJ compiler or
|
|
weaver.</para>
|
|
|
|
<remark><para>Using the AspectJ compiler and weaver enables use of the
|
|
full AspectJ language, and is discussed in <xref
|
|
linkend="aop-using-aspectj" />.</para></remark>
|
|
|
|
<section id="aop-aspectj-support">
|
|
<title>Enabling @AspectJ Support</title>
|
|
|
|
<para>To use @AspectJ aspects in a Spring configuration you need to
|
|
enable Spring support for configuring Spring AOP based on @AspectJ
|
|
aspects, and <emphasis>autoproxying</emphasis> beans based on whether or
|
|
not they are advised by those aspects. By autoproxying we mean that if
|
|
Spring determines that a bean is advised by one or more aspects, it will
|
|
automatically generate a proxy for that bean to intercept method
|
|
invocations and ensure that advice is executed as needed.</para>
|
|
|
|
<para>The @AspectJ support is enabled by including the following element
|
|
inside your spring configuration:</para>
|
|
|
|
<programlisting language="xml"><aop:aspectj-autoproxy/></programlisting>
|
|
|
|
<para>This assumes that you are using schema support as described in
|
|
<xref linkend="xsd-config" />. See <xref
|
|
linkend="xsd-config-body-schemas-aop" /> for how to import the tags in
|
|
the aop namespace.</para>
|
|
|
|
<para>If you are using the DTD, it is still possible to enable @AspectJ
|
|
support by adding the following definition to your application
|
|
context:</para>
|
|
|
|
<programlisting language="xml"><bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" /></programlisting>
|
|
|
|
<para>You will also need two AspectJ libraries on the classpath of your
|
|
application: <filename class="libraryfile">aspectjweaver.jar</filename>
|
|
and <filename class="libraryfile">aspectjrt.jar</filename>. These
|
|
libraries are available in the <filename
|
|
class="directory">'lib'</filename> directory of an AspectJ installation
|
|
(version 1.5.1 or later required), or in the <filename
|
|
class="directory">'lib/aspectj'</filename> directory of the
|
|
Spring-with-dependencies distribution.</para>
|
|
</section>
|
|
|
|
<section id="aop-at-aspectj">
|
|
<title>Declaring an aspect</title>
|
|
|
|
<para>With the @AspectJ support enabled, any bean defined in your
|
|
application context with a class that is an @AspectJ aspect (has the
|
|
<interfacename>@Aspect</interfacename> annotation) will be automatically
|
|
detected by Spring and used to configure Spring AOP. The following
|
|
example shows the minimal definition required for a not-very-useful
|
|
aspect:</para>
|
|
|
|
<para>A regular bean definition in the application context, pointing to
|
|
a bean class that has the <interfacename>@Aspect</interfacename>
|
|
annotation:</para>
|
|
|
|
<programlisting language="xml"><bean id="myAspect" class="org.xyz.NotVeryUsefulAspect">
|
|
<lineannotation><!-- configure properties of aspect here as normal --></lineannotation>
|
|
</bean>
|
|
</programlisting>
|
|
|
|
<para>And the <classname>NotVeryUsefulAspect</classname> class
|
|
definition, annotated with
|
|
<interfacename>org.aspectj.lang.annotation.Aspect</interfacename>
|
|
annotation;</para>
|
|
|
|
<programlisting language="java">package org.xyz;
|
|
import org.aspectj.lang.annotation.Aspect;
|
|
|
|
@Aspect
|
|
public class NotVeryUsefulAspect {
|
|
|
|
}</programlisting>
|
|
|
|
<para>Aspects (classes annotated with
|
|
<interfacename>@Aspect</interfacename>) may have methods and fields just
|
|
like any other class. They may also contain pointcut, advice, and
|
|
introduction (inter-type) declarations.</para>
|
|
|
|
<note>
|
|
<title>Advising aspects</title>
|
|
|
|
<para>In Spring AOP, it is <emphasis>not</emphasis> possible to have
|
|
aspects themselves be the target of advice from other aspects. The
|
|
<emphasis>@Aspect</emphasis> annotation on a class marks it as an
|
|
aspect, and hence excludes it from auto-proxying.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="aop-pointcuts">
|
|
<title>Declaring a pointcut</title>
|
|
|
|
<para>Recall that pointcuts determine join points of interest, and thus
|
|
enable us to control when advice executes. <emphasis>Spring AOP only
|
|
supports method execution join points for Spring beans</emphasis>, so
|
|
you can think of a pointcut as matching the execution of methods on
|
|
Spring beans. A pointcut declaration has two parts: a signature
|
|
comprising a name and any parameters, and a pointcut expression that
|
|
determines <emphasis>exactly</emphasis> which method executions we are
|
|
interested in. In the @AspectJ annotation-style of AOP, a pointcut
|
|
signature is provided by a regular method definition, and the pointcut
|
|
expression is indicated using the
|
|
<interfacename>@Pointcut</interfacename> annotation (the method serving
|
|
as the pointcut signature <emphasis>must</emphasis> have a
|
|
<literal>void</literal> return type).</para>
|
|
|
|
<para>An example will help make this distinction between a pointcut
|
|
signature and a pointcut expression clear. The following example defines
|
|
a pointcut named <literal>'anyOldTransfer'</literal> that will match the
|
|
execution of any method named <literal>'transfer'</literal>:</para>
|
|
|
|
<programlisting language="java">@Pointcut("execution(* transfer(..))")<lineannotation>// the pointcut expression</lineannotation>
|
|
private void anyOldTransfer() {}<lineannotation>// the pointcut signature</lineannotation></programlisting>
|
|
|
|
<para>The pointcut expression that forms the value of the
|
|
<interfacename>@Pointcut</interfacename> annotation is a regular AspectJ
|
|
5 pointcut expression. For a full discussion of AspectJ's pointcut
|
|
language, see the <ulink
|
|
url="http://www.eclipse.org/aspectj/doc/released/progguide/index.html">AspectJ
|
|
Programming Guide</ulink> (and for Java 5 based extensions, the <ulink
|
|
url="http://www.eclipse.org/aspectj/doc/released/adk15notebook/index.html">AspectJ
|
|
5 Developers Notebook</ulink>) or one of the books on AspectJ such as
|
|
<quote>Eclipse AspectJ</quote> by Colyer et. al. or <quote>AspectJ in
|
|
Action</quote> by Ramnivas Laddad.</para>
|
|
|
|
<section id="aop-pointcuts-designators">
|
|
<title>Supported Pointcut Designators</title>
|
|
|
|
<para>Spring AOP supports the following AspectJ pointcut designators
|
|
(PCD) for use in pointcut expressions:</para>
|
|
|
|
<sidebar>
|
|
<title>Other pointcut types</title>
|
|
|
|
<para>The full AspectJ pointcut language supports additional
|
|
pointcut designators that are not supported in Spring. These are:
|
|
<literal>call, get, set, preinitialization, staticinitialization,
|
|
initialization, handler, adviceexecution, withincode, cflow,
|
|
cflowbelow, if, @this</literal>, and <literal>@withincode</literal>.
|
|
Use of these pointcut designators in pointcut expressions
|
|
interpreted by Spring AOP will result in an
|
|
<classname>IllegalArgumentException</classname> being thrown.</para>
|
|
|
|
<para>The set of pointcut designators supported by Spring AOP may be
|
|
extended in future releases both to support more of the AspectJ
|
|
pointcut designators.</para>
|
|
</sidebar>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><emphasis>execution</emphasis> - for matching method
|
|
execution join points, this is the primary pointcut designator you
|
|
will use when working with Spring AOP</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>within</emphasis> - limits matching to join points
|
|
within certain types (simply the execution of a method declared
|
|
within a matching type when using Spring AOP)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>this</emphasis> - limits matching to join points
|
|
(the execution of methods when using Spring AOP) where the bean
|
|
reference (Spring AOP proxy) is an instance of the given
|
|
type</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>target</emphasis> - limits matching to join points
|
|
(the execution of methods when using Spring AOP) where the target
|
|
object (application object being proxied) is an instance of the
|
|
given type</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>args</emphasis> - limits matching to join points
|
|
(the execution of methods when using Spring AOP) where the
|
|
arguments are instances of the given types</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis><interfacename>@target</interfacename></emphasis>
|
|
- limits matching to join points (the execution of methods when
|
|
using Spring AOP) where the class of the executing object has an
|
|
annotation of the given type</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis><interfacename>@args</interfacename></emphasis> -
|
|
limits matching to join points (the execution of methods when
|
|
using Spring AOP) where the runtime type of the actual arguments
|
|
passed have annotations of the given type(s)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis><interfacename>@within</interfacename></emphasis>
|
|
- limits matching to join points within types that have the given
|
|
annotation (the execution of methods declared in types with the
|
|
given annotation when using Spring AOP)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><emphasis>@annotation</emphasis> - limits matching to join
|
|
points where the subject of the join point (method being executed
|
|
in Spring AOP) has the given annotation</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para>Because Spring AOP limits matching to only method execution
|
|
join points, the discussion of the pointcut designators above gives a
|
|
narrower definition than you will find in the AspectJ programming
|
|
guide. In addition, AspectJ itself has type-based semantics and at an
|
|
execution join point both '<literal>this</literal>' and
|
|
'<literal>target</literal>' refer to the same object - the object
|
|
executing the method. Spring AOP is a proxy-based system and
|
|
differentiates between the proxy object itself (bound to
|
|
'<literal>this</literal>') and the target object behind the proxy
|
|
(bound to '<literal>target</literal>').</para>
|
|
|
|
<note>
|
|
<para>Due to the proxy-based nature of Spring's AOP framework,
|
|
protected methods are by definition <emphasis>not</emphasis>
|
|
intercepted, neither for JDK proxies (where this isn't applicable)
|
|
nor for CGLIB proxies (where this is technically possible but not
|
|
recommendable for AOP purposes). As a consequence, any given pointcut
|
|
will be matched against <emphasis>public methods only</emphasis>!</para>
|
|
|
|
<para>If your interception needs include protected/private methods
|
|
or even constructors, consider the use of Spring-driven
|
|
<link linkend="aop-aj-ltw">native AspectJ weaving</link> instead
|
|
of Spring's proxy-based AOP framework. This constitutes a different
|
|
mode of AOP usage with different characteristics, so be sure to make
|
|
yourself familiar with weaving first before making a decision.</para>
|
|
</note>
|
|
|
|
<para>Spring AOP also supports an additional PCD named
|
|
'<literal>bean</literal>'. This PCD allows you to limit the matching
|
|
of join points to a particular named Spring bean, or to a set of named
|
|
Spring beans (when using wildcards). The '<literal>bean</literal>' PCD
|
|
has the following form:</para>
|
|
|
|
<programlisting language="java">bean(idOrNameOfBean)</programlisting>
|
|
|
|
<para>The '<literal>idOrNameOfBean</literal>' token can be the name of
|
|
any Spring bean: limited wildcard support using the
|
|
'<literal>*</literal>' character is provided, so if you establish
|
|
some naming conventions for your Spring beans you can quite easily
|
|
write a '<literal>bean</literal>' PCD expression to pick them out. As
|
|
is the case with other pointcut designators, the
|
|
'<literal>bean</literal>' PCD can be &&'ed, ||'ed, and !
|
|
(negated) too.</para>
|
|
|
|
<note>
|
|
<para>Please note that the '<literal>bean</literal>' PCD is
|
|
<emphasis>only</emphasis> supported in Spring AOP - and
|
|
<emphasis>not</emphasis> in native AspectJ weaving. It is a
|
|
Spring-specific extension to the standard PCDs that AspectJ
|
|
defines.</para>
|
|
|
|
<para>The '<literal>bean</literal>' PCD operates at the
|
|
<emphasis>instance</emphasis> level (building on the Spring
|
|
bean name concept) rather than at the type level only
|
|
(which is what weaving-based AOP is limited to).
|
|
Instance-based pointcut designators are a special capability
|
|
of Spring's proxy-based AOP framework and its close integration
|
|
with the Spring bean factory, where it is natural and
|
|
straightforward to identify specific beans by name.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="aop-pointcuts-combining">
|
|
<title>Combining pointcut expressions</title>
|
|
|
|
<para>Pointcut expressions can be combined using '&&', '||'
|
|
and '!'. It is also possible to refer to pointcut expressions by name.
|
|
The following example shows three pointcut expressions:
|
|
<literal>anyPublicOperation</literal> (which matches if a method
|
|
execution join point represents the execution of any public method);
|
|
<literal>inTrading</literal> (which matches if a method execution is
|
|
in the trading module), and <literal>tradingOperation</literal> (which
|
|
matches if a method execution represents any public method in the
|
|
trading module).</para>
|
|
|
|
<programlisting language="java"> @Pointcut("execution(public * *(..))")
|
|
private void anyPublicOperation() {}
|
|
|
|
@Pointcut("within(com.xyz.someapp.trading..*)")
|
|
private void inTrading() {}
|
|
|
|
@Pointcut("anyPublicOperation() && inTrading()")
|
|
private void tradingOperation() {}</programlisting>
|
|
|
|
<para>It is a best practice to build more complex pointcut expressions
|
|
out of smaller named components as shown above. When referring to
|
|
pointcuts by name, normal Java visibility rules apply (you can see
|
|
private pointcuts in the same type, protected pointcuts in the
|
|
hierarchy, public pointcuts anywhere and so on). Visibility does not
|
|
affect pointcut <emphasis>matching</emphasis>.</para>
|
|
</section>
|
|
|
|
<section id="aop-common-pointcuts">
|
|
<title>Sharing common pointcut definitions</title>
|
|
|
|
<para>When working with enterprise applications, you often want to
|
|
refer to modules of the application and particular sets of operations
|
|
from within several aspects. We recommend defining a
|
|
"SystemArchitecture" aspect that captures common pointcut expressions
|
|
for this purpose. A typical such aspect would look as follows:</para>
|
|
|
|
<programlisting language="java">package com.xyz.someapp;
|
|
|
|
import org.aspectj.lang.annotation.Aspect;
|
|
import org.aspectj.lang.annotation.Pointcut;
|
|
|
|
@Aspect
|
|
public class SystemArchitecture {
|
|
|
|
<lineannotation>/**
|
|
* A join point is in the web layer if the method is defined
|
|
* in a type in the com.xyz.someapp.web package or any sub-package
|
|
* under that.
|
|
*/</lineannotation>
|
|
@Pointcut("within(com.xyz.someapp.web..*)")
|
|
public void inWebLayer() {}
|
|
|
|
<lineannotation>/**
|
|
* A join point is in the service layer if the method is defined
|
|
* in a type in the <literal>com.xyz.someapp.service</literal> package or any sub-package
|
|
* under that.
|
|
*/</lineannotation>
|
|
@Pointcut("within(com.xyz.someapp.service..*)")
|
|
public void inServiceLayer() {}
|
|
|
|
<lineannotation>/**
|
|
* A join point is in the data access layer if the method is defined
|
|
* in a type in the <literal>com.xyz.someapp.dao</literal> package or any sub-package
|
|
* under that.
|
|
*/</lineannotation>
|
|
@Pointcut("within(com.xyz.someapp.dao..*)")
|
|
public void inDataAccessLayer() {}
|
|
|
|
<lineannotation>/**
|
|
* A business service is the execution of any method defined on a service
|
|
* interface. This definition assumes that interfaces are placed in the
|
|
* "service" package, and that implementation types are in sub-packages.
|
|
*
|
|
* If you group service interfaces by functional area (for example,
|
|
* in packages <literal>com.xyz.someapp.abc.service</literal> and <literal>com.xyz.def.service</literal>) then
|
|
* the pointcut expression "<literal>execution(* com.xyz.someapp..service.*.*(..))</literal>"
|
|
* could be used instead.
|
|
*
|
|
* Alternatively, you can write the expression using the '<literal>bean</literal>'
|
|
* PCD, like so "<literal>bean(*Service)</literal>". (This assumes that you have
|
|
* named your Spring service beans in a consistent fashion.)
|
|
*/</lineannotation>
|
|
@Pointcut("execution(* com.xyz.someapp.service.*.*(..))")
|
|
public void businessService() {}
|
|
|
|
<lineannotation>/**
|
|
* A data access operation is the execution of any method defined on a
|
|
* dao interface. This definition assumes that interfaces are placed in the
|
|
* "<literal>dao</literal>" package, and that implementation types are in sub-packages.
|
|
*/</lineannotation>
|
|
@Pointcut("execution(* com.xyz.someapp.dao.*.*(..))")
|
|
public void dataAccessOperation() {}
|
|
|
|
}</programlisting>
|
|
|
|
<para>The pointcuts defined in such an aspect can be referred to
|
|
anywhere that you need a pointcut expression. For example, to make the
|
|
service layer transactional, you could write:</para>
|
|
|
|
<programlisting language="xml"><aop:config>
|
|
<aop:advisor
|
|
pointcut="com.xyz.someapp.SystemArchitecture.businessService()"
|
|
advice-ref="tx-advice"/>
|
|
</aop:config>
|
|
|
|
<tx:advice id="tx-advice">
|
|
<tx:attributes>
|
|
<tx:method name="*" propagation="REQUIRED"/>
|
|
</tx:attributes>
|
|
</tx:advice></programlisting>
|
|
|
|
<para>The <literal><aop:config></literal> and
|
|
<literal><aop:advisor></literal> elements are discussed in <xref
|
|
linkend="aop-schema" />. The transaction elements are discussed in
|
|
<xref linkend="transaction" />.</para>
|
|
</section>
|
|
|
|
<section id="aop-pointcuts-examples">
|
|
<title>Examples</title>
|
|
|
|
<para>Spring AOP users are likely to use the
|
|
<literal>execution</literal> pointcut designator the most often. The
|
|
format of an execution expression is:</para>
|
|
|
|
<programlisting language="java">execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
|
|
throws-pattern?)</programlisting>
|
|
|
|
<para>All parts except the returning type pattern (ret-type-pattern in
|
|
the snippet above), name pattern, and parameters pattern are optional.
|
|
The returning type pattern determines what the return type of the
|
|
method must be in order for a join point to be matched. Most
|
|
frequently you will use <literal>*</literal> as the returning type
|
|
pattern, which matches any return type. A fully-qualified type name
|
|
will match only when the method returns the given type. The name
|
|
pattern matches the method name. You can use the <literal>*</literal>
|
|
wildcard as all or part of a name pattern. The parameters pattern is
|
|
slightly more complex: <literal>()</literal> matches a method that
|
|
takes no parameters, whereas <literal>(..)</literal> matches any
|
|
number of parameters (zero or more). The pattern
|
|
<literal>(*)</literal> matches a method taking one parameter of any
|
|
type, <literal>(*,String)</literal> matches a method taking two
|
|
parameters, the first can be of any type, the second must be a String.
|
|
Consult the <ulink
|
|
url="http://www.eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.html">
|
|
Language Semantics</ulink> section of the AspectJ Programming Guide
|
|
for more information.</para>
|
|
|
|
<para>Some examples of common pointcut expressions are given
|
|
below.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>the execution of any public method:</para>
|
|
|
|
<programlisting language="java">execution(public * *(..))</programlisting>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>the execution of any method with a name beginning with
|
|
"set":</para>
|
|
|
|
<programlisting language="java">execution(* set*(..))</programlisting>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>the execution of any method defined by the
|
|
<interfacename>AccountService</interfacename> interface:</para>
|
|
|
|
<programlisting language="java">execution(* com.xyz.service.AccountService.*(..))</programlisting>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>the execution of any method defined in the service
|
|
package:</para>
|
|
|
|
<programlisting language="java">execution(* com.xyz.service.*.*(..))</programlisting>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>the execution of any method defined in the service package
|
|
or a sub-package:</para>
|
|
|
|
<programlisting language="java">execution(* com.xyz.service..*.*(..))</programlisting>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>any join point (method execution only in Spring AOP) within
|
|
the service package:</para>
|
|
|
|
<programlisting language="java">within(com.xyz.service.*)</programlisting>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>any join point (method execution only in Spring AOP) within
|
|
the service package or a sub-package:</para>
|
|
|
|
<programlisting language="java">within(com.xyz.service..*)</programlisting>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>any join point (method execution only in Spring AOP) where
|
|
the proxy implements the
|
|
<interfacename>AccountService</interfacename> interface:</para>
|
|
|
|
<programlisting language="java">this(com.xyz.service.AccountService)</programlisting>
|
|
|
|
<remark><para>'this' is more commonly used in a binding form :-
|
|
see the following section on advice for how to make the proxy
|
|
object available in the advice body.</para></remark>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>any join point (method execution only in Spring AOP) where
|
|
the target object implements the
|
|
<interfacename>AccountService</interfacename> interface:</para>
|
|
|
|
<programlisting language="java">target(com.xyz.service.AccountService)</programlisting>
|
|
|
|
<remark><para>'target' is more commonly used in a binding form :-
|
|
see the following section on advice for how to make the target
|
|
object available in the advice body.</para></remark>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>any join point (method execution only in Spring AOP) which
|
|
takes a single parameter, and where the argument passed at runtime
|
|
is <interfacename>Serializable</interfacename>:</para>
|
|
|
|
<programlisting language="java">args(java.io.Serializable)</programlisting>
|
|
|
|
<remark>'args' is more commonly used in a binding form :- see the
|
|
following section on advice for how to make the method arguments
|
|
available in the advice body.</remark>
|
|
|
|
<para>Note that the pointcut given in this example is different to
|
|
<literal>execution(* *(java.io.Serializable))</literal>: the args
|
|
version matches if the argument passed at runtime is Serializable,
|
|
the execution version matches if the method signature declares a
|
|
single parameter of type
|
|
<interfacename>Serializable</interfacename>.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>any join point (method execution only in Spring AOP) where
|
|
the target object has an
|
|
<interfacename>@Transactional</interfacename> annotation:</para>
|
|
|
|
<programlisting language="java">@target(org.springframework.transaction.annotation.Transactional)</programlisting>
|
|
|
|
<remark><para>'@target' can also be used in a binding form :- see
|
|
the following section on advice for how to make the annotation
|
|
object available in the advice body.</para></remark>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>any join point (method execution only in Spring AOP) where
|
|
the declared type of the target object has an
|
|
<interfacename>@Transactional</interfacename> annotation:</para>
|
|
|
|
<programlisting language="java">@within(org.springframework.transaction.annotation.Transactional)</programlisting>
|
|
|
|
<remark><para>'@within' can also be used in a binding form :- see
|
|
the following section on advice for how to make the annotation
|
|
object available in the advice body.</para></remark>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>any join point (method execution only in Spring AOP) where
|
|
the executing method has an
|
|
<interfacename>@Transactional</interfacename> annotation:</para>
|
|
|
|
<programlisting language="java">@annotation(org.springframework.transaction.annotation.Transactional)</programlisting>
|
|
|
|
<remark><para>'@annotation' can also be used in a binding form :-
|
|
see the following section on advice for how to make the annotation
|
|
object available in the advice body.</para></remark>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>any join point (method execution only in Spring AOP) which
|
|
takes a single parameter, and where the runtime type of the
|
|
argument passed has the <interfacename>@Classified</interfacename>
|
|
annotation:</para>
|
|
|
|
<programlisting language="java">@args(com.xyz.security.Classified)</programlisting>
|
|
|
|
<remark><para>'@args' can also be used in a binding form :- see
|
|
the following section on advice for how to make the annotation
|
|
object(s) available in the advice body.</para></remark>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>any join point (method execution only in Spring AOP) on a
|
|
Spring bean named '<literal>tradeService</literal>':</para>
|
|
|
|
<programlisting language="java">bean(tradeService)</programlisting>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>any join point (method execution only in Spring AOP) on
|
|
Spring beans having names that match the wildcard expression
|
|
'<literal>*Service</literal>':</para>
|
|
|
|
<programlisting language="java">bean(*Service)</programlisting>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="aop-advice">
|
|
<title>Declaring advice</title>
|
|
|
|
<para>Advice is associated with a pointcut expression, and runs before,
|
|
after, or around method executions matched by the pointcut. The pointcut
|
|
expression may be either a simple reference to a named pointcut, or a
|
|
pointcut expression declared in place.</para>
|
|
|
|
<section id="aop-advice-before">
|
|
<title>Before advice</title>
|
|
|
|
<para>Before advice is declared in an aspect using the
|
|
<interfacename>@Before</interfacename> annotation:</para>
|
|
|
|
<programlisting language="java">import org.aspectj.lang.annotation.Aspect;
|
|
import org.aspectj.lang.annotation.Before;
|
|
|
|
@Aspect
|
|
public class BeforeExample {
|
|
|
|
@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
|
|
public void doAccessCheck() {
|
|
<lineannotation>// ...</lineannotation>
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>If using an in-place pointcut expression we could rewrite the
|
|
above example as:</para>
|
|
|
|
<programlisting language="java">import org.aspectj.lang.annotation.Aspect;
|
|
import org.aspectj.lang.annotation.Before;
|
|
|
|
@Aspect
|
|
public class BeforeExample {
|
|
|
|
@Before("execution(* com.xyz.myapp.dao.*.*(..))")
|
|
public void doAccessCheck() {
|
|
<lineannotation>// ...</lineannotation>
|
|
}
|
|
|
|
}</programlisting>
|
|
</section>
|
|
|
|
<section id="aop-advice-after-returning">
|
|
<title>After returning advice</title>
|
|
|
|
<para>After returning advice runs when a matched method execution
|
|
returns normally. It is declared using the
|
|
<interfacename>@AfterReturning</interfacename> annotation:</para>
|
|
|
|
<programlisting language="java">import org.aspectj.lang.annotation.Aspect;
|
|
import org.aspectj.lang.annotation.AfterReturning;
|
|
|
|
@Aspect
|
|
public class AfterReturningExample {
|
|
|
|
@AfterReturning("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
|
|
public void doAccessCheck() {
|
|
<lineannotation>// ...</lineannotation>
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<remark>Note: it is of course possible to have multiple advice
|
|
declarations, and other members as well, all inside the same aspect.
|
|
We're just showing a single advice declaration in these examples to
|
|
focus on the issue under discussion at the time.</remark>
|
|
|
|
<para>Sometimes you need access in the advice body to the actual value
|
|
that was returned. You can use the form of
|
|
<interfacename>@AfterReturning</interfacename> that binds the return
|
|
value for this:</para>
|
|
|
|
<programlisting language="java">import org.aspectj.lang.annotation.Aspect;
|
|
import org.aspectj.lang.annotation.AfterReturning;
|
|
|
|
@Aspect
|
|
public class AfterReturningExample {
|
|
|
|
@AfterReturning(
|
|
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
|
|
returning="retVal")
|
|
public void doAccessCheck(Object retVal) {
|
|
<lineannotation>// ...</lineannotation>
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>The name used in the <literal>returning</literal> attribute must
|
|
correspond to the name of a parameter in the advice method. When a
|
|
method execution returns, the return value will be passed to the
|
|
advice method as the corresponding argument value. A
|
|
<literal>returning</literal> clause also restricts matching to only
|
|
those method executions that return a value of the specified type
|
|
(<classname>Object</classname> in this case, which will match any
|
|
return value).</para>
|
|
|
|
<para>Please note that it is <emphasis>not</emphasis> possible to
|
|
return a totally different reference when using after-returning
|
|
advice.</para>
|
|
</section>
|
|
|
|
<section id="aop-advice-after-throwing">
|
|
<title>After throwing advice</title>
|
|
|
|
<para>After throwing advice runs when a matched method execution exits
|
|
by throwing an exception. It is declared using the
|
|
<interfacename>@AfterThrowing</interfacename> annotation:</para>
|
|
|
|
<programlisting language="java">import org.aspectj.lang.annotation.Aspect;
|
|
import org.aspectj.lang.annotation.AfterThrowing;
|
|
|
|
@Aspect
|
|
public class AfterThrowingExample {
|
|
|
|
@AfterThrowing("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
|
|
public void doRecoveryActions() {
|
|
<lineannotation>// ...</lineannotation>
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>Often you want the advice to run only when exceptions of a given
|
|
type are thrown, and you also often need access to the thrown
|
|
exception in the advice body. Use the <literal>throwing</literal>
|
|
attribute to both restrict matching (if desired, use
|
|
<interfacename>Throwable</interfacename> as the exception type
|
|
otherwise) and bind the thrown exception to an advice
|
|
parameter.</para>
|
|
|
|
<programlisting language="java">import org.aspectj.lang.annotation.Aspect;
|
|
import org.aspectj.lang.annotation.AfterThrowing;
|
|
|
|
@Aspect
|
|
public class AfterThrowingExample {
|
|
|
|
@AfterThrowing(
|
|
pointcut="com.xyz.myapp.SystemArchitecture.dataAccessOperation()",
|
|
throwing="ex")
|
|
public void doRecoveryActions(DataAccessException ex) {
|
|
<lineannotation>// ...</lineannotation>
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>The name used in the <literal>throwing</literal> attribute must
|
|
correspond to the name of a parameter in the advice method. When a
|
|
method execution exits by throwing an exception, the exception will be
|
|
passed to the advice method as the corresponding argument value. A
|
|
<literal>throwing</literal> clause also restricts matching to only
|
|
those method executions that throw an exception of the specified type
|
|
(<classname>DataAccessException</classname> in this case).</para>
|
|
</section>
|
|
|
|
<section id="aop-advice-after-finally">
|
|
<title>After (finally) advice</title>
|
|
|
|
<para>After (finally) advice runs however a matched method execution
|
|
exits. It is declared using the <interfacename>@After</interfacename>
|
|
annotation. After advice must be prepared to handle both normal and
|
|
exception return conditions. It is typically used for releasing
|
|
resources, etc.</para>
|
|
|
|
<programlisting language="java">import org.aspectj.lang.annotation.Aspect;
|
|
import org.aspectj.lang.annotation.After;
|
|
|
|
@Aspect
|
|
public class AfterFinallyExample {
|
|
|
|
@After("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
|
|
public void doReleaseLock() {
|
|
<lineannotation>// ...</lineannotation>
|
|
}
|
|
|
|
}</programlisting>
|
|
</section>
|
|
|
|
<section id="aop-ataspectj-around-advice">
|
|
<title>Around advice</title>
|
|
|
|
<para>The final kind of advice is around advice. Around advice runs
|
|
"around" a matched method execution. It has the opportunity to do work
|
|
both before and after the method executes, and to determine when, how,
|
|
and even if, the method actually gets to execute at all. Around advice
|
|
is often used if you need to share state before and after a method
|
|
execution in a thread-safe manner (starting and stopping a timer for
|
|
example). Always use the least powerful form of advice that meets your
|
|
requirements (i.e. don't use around advice if simple before advice
|
|
would do).</para>
|
|
|
|
<para>Around advice is declared using the
|
|
<interfacename>@Around</interfacename> annotation. The first parameter
|
|
of the advice method must be of type
|
|
<interfacename>ProceedingJoinPoint</interfacename>. Within the body of
|
|
the advice, calling <literal>proceed()</literal> on the
|
|
<interfacename>ProceedingJoinPoint</interfacename> causes the
|
|
underlying method to execute. The <literal>proceed</literal> method
|
|
may also be called passing in an <classname>Object[]</classname> - the
|
|
values in the array will be used as the arguments to the method
|
|
execution when it proceeds.</para>
|
|
|
|
<remark>The behavior of proceed when called with an
|
|
<classname>Object[]</classname> is a little different than the
|
|
behavior of proceed for around advice compiled by the AspectJ
|
|
compiler. For around advice written using the traditional AspectJ
|
|
language, the number of arguments passed to proceed must match the
|
|
number of arguments passed to the around advice (not the number of
|
|
arguments taken by the underlying join point), and the value passed to
|
|
proceed in a given argument position supplants the original value at
|
|
the join point for the entity the value was bound to (Don't worry if
|
|
this doesn't make sense right now!). The approach taken by Spring is
|
|
simpler and a better match to its proxy-based, execution only
|
|
semantics. You only need to be aware of this difference if you are
|
|
compiling @AspectJ aspects written for Spring and using proceed with
|
|
arguments with the AspectJ compiler and weaver. There is a way to
|
|
write such aspects that is 100% compatible across both Spring AOP and
|
|
AspectJ, and this is discussed in the following section on advice
|
|
parameters.</remark>
|
|
|
|
<programlisting language="java">import org.aspectj.lang.annotation.Aspect;
|
|
import org.aspectj.lang.annotation.Around;
|
|
import org.aspectj.lang.ProceedingJoinPoint;
|
|
|
|
@Aspect
|
|
public class AroundExample {
|
|
|
|
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
|
|
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
|
|
// start stopwatch
|
|
Object retVal = pjp.proceed();
|
|
// stop stopwatch
|
|
return retVal;
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>The value returned by the around advice will be the return value
|
|
seen by the caller of the method. A simple caching aspect for example
|
|
could return a value from a cache if it has one, and invoke proceed()
|
|
if it does not. Note that proceed may be invoked once, many times, or
|
|
not at all within the body of the around advice, all of these are
|
|
quite legal.</para>
|
|
</section>
|
|
|
|
<section id="aop-ataspectj-advice-params">
|
|
<title>Advice parameters</title>
|
|
|
|
<para>Spring 2.0 offers fully typed advice - meaning that you declare
|
|
the parameters you need in the advice signature (as we saw for the
|
|
returning and throwing examples above) rather than work with
|
|
<classname>Object[]</classname> arrays all the time. We'll see how to
|
|
make argument and other contextual values available to the advice body
|
|
in a moment. First let's take a look at how to write generic advice
|
|
that can find out about the method the advice is currently
|
|
advising.</para>
|
|
|
|
<section id="aop-ataspectj-advice-params-the-joinpoint">
|
|
<title>Access to the current
|
|
<interfacename>JoinPoint</interfacename></title>
|
|
|
|
<para>Any advice method may declare as its first parameter, a
|
|
parameter of type
|
|
<interfacename>org.aspectj.lang.JoinPoint</interfacename> (please
|
|
note that around advice is <emphasis>required</emphasis> to declare
|
|
a first parameter of type
|
|
<interfacename>ProceedingJoinPoint</interfacename>, which is a
|
|
subclass of <interfacename>JoinPoint</interfacename>. The
|
|
<interfacename>JoinPoint</interfacename> interface provides a number
|
|
of useful methods such as <literal>getArgs()</literal> (returns the
|
|
method arguments), <methodname>getThis()</methodname> (returns the
|
|
proxy object), <methodname>getTarget()</methodname> (returns the
|
|
target object), <methodname>getSignature()</methodname> (returns a
|
|
description of the method that is being advised) and
|
|
<methodname>toString()</methodname> (prints a useful description of
|
|
the method being advised). Please do consult the Javadocs for full
|
|
details.</para>
|
|
</section>
|
|
|
|
<section id="aop-ataspectj-advice-params-passing">
|
|
<title>Passing parameters to advice</title>
|
|
|
|
<para>We've already seen how to bind the returned value or exception
|
|
value (using after returning and after throwing advice). To make
|
|
argument values available to the advice body, you can use the
|
|
binding form of <literal>args</literal>. If a parameter name is used
|
|
in place of a type name in an args expression, then the value of the
|
|
corresponding argument will be passed as the parameter value when
|
|
the advice is invoked. An example should make this clearer. Suppose
|
|
you want to advise the execution of dao operations that take an
|
|
Account object as the first parameter, and you need access to the
|
|
account in the advice body. You could write the following:</para>
|
|
|
|
<programlisting language="java">@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
|
|
"args(account,..)")
|
|
public void validateAccount(Account account) {
|
|
<lineannotation>// ...</lineannotation>
|
|
}</programlisting>
|
|
|
|
<para>The <literal>args(account,..)</literal> part of the pointcut
|
|
expression serves two purposes: firstly, it restricts matching to
|
|
only those method executions where the method takes at least one
|
|
parameter, and the argument passed to that parameter is an instance
|
|
of <classname>Account</classname>; secondly, it makes the actual
|
|
<classname>Account</classname> object available to the advice via
|
|
the <literal>account</literal> parameter.</para>
|
|
|
|
<para>Another way of writing this is to declare a pointcut that
|
|
"provides" the <classname>Account</classname> object value when it
|
|
matches a join point, and then just refer to the named pointcut from
|
|
the advice. This would look as follows:</para>
|
|
|
|
<programlisting language="java">@Pointcut("com.xyz.myapp.SystemArchitecture.dataAccessOperation() &&" +
|
|
"args(account,..)")
|
|
private void accountDataAccessOperation(Account account) {}
|
|
|
|
@Before("accountDataAccessOperation(account)")
|
|
public void validateAccount(Account account) {
|
|
<lineannotation>// ...</lineannotation>
|
|
}</programlisting>
|
|
|
|
<para>The interested reader is once more referred to the AspectJ
|
|
programming guide for more details.</para>
|
|
|
|
<para>The proxy object (<literal>this</literal>), target object
|
|
(<literal>target</literal>), and annotations (<literal>@within,
|
|
@target, @annotation, @args</literal>) can all be bound in a similar
|
|
fashion. The following example shows how you could match the
|
|
execution of methods annotated with an
|
|
<interfacename>@Auditable</interfacename> annotation, and extract
|
|
the audit code.</para>
|
|
|
|
<para>First the definition of the
|
|
<interfacename>@Auditable</interfacename> annotation:</para>
|
|
|
|
<programlisting language="java">@Retention(RetentionPolicy.RUNTIME)
|
|
@Target(ElementType.METHOD)
|
|
public @interface Auditable {
|
|
AuditCode value();
|
|
}</programlisting>
|
|
|
|
<para>And then the advice that matches the execution of
|
|
<interfacename>@Auditable</interfacename> methods:</para>
|
|
|
|
<programlisting language="java">@Before("com.xyz.lib.Pointcuts.anyPublicMethod() && " +
|
|
"@annotation(auditable)")
|
|
public void audit(Auditable auditable) {
|
|
AuditCode code = auditable.value();
|
|
<lineannotation>// ...</lineannotation>
|
|
}</programlisting>
|
|
</section>
|
|
|
|
<section id="aop-ataspectj-advice-params-names">
|
|
<title>Determining argument names</title>
|
|
|
|
<para>The parameter binding in advice invocations relies on matching
|
|
names used in pointcut expressions to declared parameter names in
|
|
(advice and pointcut) method signatures. Parameter names are
|
|
<emphasis>not</emphasis> available through Java reflection, so
|
|
Spring AOP uses the following strategies to determine parameter
|
|
names:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para>If the parameter names have been specified by the user
|
|
explicitly, then the specified parameter names are used: both
|
|
the advice and the pointcut annotations have an optional
|
|
"argNames" attribute which can be used to specify the argument
|
|
names of the annotated method - these argument names
|
|
<emphasis>are</emphasis> available at runtime. For
|
|
example:</para>
|
|
|
|
<programlisting language="java">@Before(
|
|
value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)",
|
|
argNames="bean,auditable")
|
|
public void audit(Object bean, Auditable auditable) {
|
|
AuditCode code = auditable.value();
|
|
<lineannotation>// ... use code and bean</lineannotation>
|
|
}</programlisting>
|
|
|
|
<para>If the first parameter is of the
|
|
<interfacename>JoinPoint</interfacename>,
|
|
<interfacename>ProceedingJoinPoint</interfacename>, or
|
|
<interfacename>JoinPoint.StaticPart</interfacename> type, you
|
|
may leave out the name of the parameter from the value of the
|
|
"argNames" attribute. For example, if you modify the preceding
|
|
advice to receive the join point object, the "argNames"
|
|
attribute need not include it:</para>
|
|
|
|
<programlisting language="java">@Before(
|
|
value="com.xyz.lib.Pointcuts.anyPublicMethod() && target(bean) && @annotation(auditable)",
|
|
argNames="bean,auditable")
|
|
public void audit(JoinPoint jp, Object bean, Auditable auditable) {
|
|
AuditCode code = auditable.value();
|
|
<lineannotation>// ... use code, bean, and jp</lineannotation>
|
|
}</programlisting>
|
|
|
|
<para>The special treatment given to the first parameter of the
|
|
<interfacename>JoinPoint</interfacename>,
|
|
<interfacename>ProceedingJoinPoint</interfacename>, and
|
|
<interfacename>JoinPoint.StaticPart</interfacename> types is
|
|
particularly convenient for advice that do not collect any other
|
|
join point context. In such situations, you may simply omit the
|
|
"argNames" attribute. For example, the following advice need not
|
|
declare the "argNames" attribute:</para>
|
|
|
|
<programlisting language="java">@Before(
|
|
"com.xyz.lib.Pointcuts.anyPublicMethod()")
|
|
public void audit(JoinPoint jp) {
|
|
<lineannotation>// ... use jp</lineannotation>
|
|
}</programlisting>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>Using the <literal>'argNames'</literal> attribute is a
|
|
little clumsy, so if the <literal>'argNames'</literal> attribute
|
|
has not been specified, then Spring AOP will look at the debug
|
|
information for the class and try to determine the parameter
|
|
names from the local variable table. This information will be
|
|
present as long as the classes have been compiled with debug
|
|
information (<literal>'-g:vars'</literal> at a minimum). The
|
|
consequences of compiling with this flag on are: (1) your code
|
|
will be slightly easier to understand (reverse engineer), (2)
|
|
the class file sizes will be very slightly bigger (typically
|
|
inconsequential), (3) the optimization to remove unused local
|
|
variables will not be applied by your compiler. In other words,
|
|
you should encounter no difficulties building with this flag
|
|
on.</para>
|
|
|
|
<remark>If an @AspectJ aspect has been compiled by the AspectJ
|
|
compiler (ajc) even without the debug information then there is
|
|
no need to add the <literal>argNames</literal> attribute as the
|
|
compiler will retain the needed information.</remark>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>If the code has been compiled without the necessary debug
|
|
information, then Spring AOP will attempt to deduce the pairing
|
|
of binding variables to parameters (for example, if only one
|
|
variable is bound in the pointcut expression, and the advice
|
|
method only takes one parameter, the pairing is obvious!). If
|
|
the binding of variables is ambiguous given the available
|
|
information, then an
|
|
<exceptionname>AmbiguousBindingException</exceptionname> will be
|
|
thrown.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>If all of the above strategies fail then an
|
|
<exceptionname>IllegalArgumentException</exceptionname> will be
|
|
thrown.</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</section>
|
|
|
|
<section id="aop-ataspectj-advice-proceeding-with-the-call">
|
|
<title>Proceeding with arguments</title>
|
|
|
|
<para>We remarked earlier that we would describe how to write a
|
|
proceed call <emphasis>with arguments</emphasis> that works
|
|
consistently across Spring AOP and AspectJ. The solution is simply
|
|
to ensure that the advice signature binds each of the method
|
|
parameters in order. For example:</para>
|
|
|
|
<programlisting language="java">@Around("execution(List<Account> find*(..)) &&" +
|
|
"com.xyz.myapp.SystemArchitecture.inDataAccessLayer() && " +
|
|
"args(accountHolderNamePattern)")
|
|
public Object preProcessQueryPattern(ProceedingJoinPoint pjp, String accountHolderNamePattern)
|
|
throws Throwable {
|
|
String newPattern = preProcess(accountHolderNamePattern);
|
|
return pjp.proceed(new Object[] {newPattern});
|
|
}
|
|
</programlisting>
|
|
|
|
<para>In many cases you will be doing this binding anyway (as in the
|
|
example above).</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="aop-ataspectj-advice-ordering">
|
|
<title>Advice ordering</title>
|
|
|
|
<para>What happens when multiple pieces of advice all want to run at
|
|
the same join point? Spring AOP follows the same precedence rules as
|
|
AspectJ to determine the order of advice execution. The highest
|
|
precedence advice runs first "on the way in" (so given two pieces of
|
|
before advice, the one with highest precedence runs first). "On the
|
|
way out" from a join point, the highest precedence advice runs last
|
|
(so given two pieces of after advice, the one with the highest
|
|
precedence will run second).</para>
|
|
|
|
<para>When two pieces of advice defined in
|
|
<emphasis>different</emphasis> aspects both need to run at the same
|
|
join point, unless you specify otherwise the order of execution is
|
|
undefined. You can control the order of execution by specifying
|
|
precedence. This is done in the normal Spring way by either
|
|
implementing the
|
|
<interfacename>org.springframework.core.Ordered</interfacename>
|
|
interface in the aspect class or annotating it with the
|
|
<interfacename>Order</interfacename> annotation. Given two aspects,
|
|
the aspect returning the lower value from
|
|
<literal>Ordered.getValue()</literal> (or the annotation value) has
|
|
the higher precedence.</para>
|
|
|
|
<para>When two pieces of advice defined in <emphasis>the
|
|
same</emphasis> aspect both need to run at the same join point, the
|
|
ordering is undefined (since there is no way to retrieve the
|
|
declaration order via reflection for javac-compiled classes). Consider
|
|
collapsing such advice methods into one advice method per join point
|
|
in each aspect class, or refactor the pieces of advice into separate
|
|
aspect classes - which can be ordered at the aspect level.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="aop-introductions">
|
|
<title>Introductions</title>
|
|
|
|
<para>Introductions (known as inter-type declarations in AspectJ) enable
|
|
an aspect to declare that advised objects implement a given interface,
|
|
and to provide an implementation of that interface on behalf of those
|
|
objects.</para>
|
|
|
|
<para>An introduction is made using the
|
|
<interfacename>@DeclareParents</interfacename> annotation. This
|
|
annotation is used to declare that matching types have a new parent
|
|
(hence the name). For example, given an interface
|
|
<interfacename>UsageTracked</interfacename>, and an implementation of
|
|
that interface <classname>DefaultUsageTracked</classname>, the following
|
|
aspect declares that all implementors of service interfaces also
|
|
implement the <interfacename>UsageTracked</interfacename> interface. (In
|
|
order to expose statistics via JMX for example.)</para>
|
|
|
|
<programlisting language="java">@Aspect
|
|
public class UsageTracking {
|
|
|
|
@DeclareParents(value="com.xzy.myapp.service.*+",
|
|
defaultImpl=DefaultUsageTracked.class)
|
|
public static UsageTracked mixin;
|
|
|
|
@Before("com.xyz.myapp.SystemArchitecture.businessService() &&" +
|
|
"this(usageTracked)")
|
|
public void recordUsage(UsageTracked usageTracked) {
|
|
usageTracked.incrementUseCount();
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>The interface to be implemented is determined by the type of the
|
|
annotated field. The <literal>value</literal> attribute of the
|
|
<interfacename>@DeclareParents</interfacename> annotation is an AspectJ
|
|
type pattern :- any bean of a matching type will implement the
|
|
UsageTracked interface. Note that in the before advice of the above
|
|
example, service beans can be directly used as implementations of the
|
|
<interfacename>UsageTracked</interfacename> interface. If accessing a
|
|
bean programmatically you would write the following:</para>
|
|
|
|
<programlisting language="java">UsageTracked usageTracked = (UsageTracked) context.getBean("myService");</programlisting>
|
|
</section>
|
|
|
|
<section id="aop-instantiation-models">
|
|
<title>Aspect instantiation models</title>
|
|
|
|
<remark>(This is an advanced topic, so if you are just starting out with
|
|
AOP you can safely skip it until later.)</remark>
|
|
|
|
<para>By default there will be a single instance of each aspect within
|
|
the application context. AspectJ calls this the singleton instantiation
|
|
model. It is possible to define aspects with alternate lifecycles :-
|
|
Spring supports AspectJ's <literal>perthis</literal> and
|
|
<literal>pertarget</literal> instantiation models (<literal>percflow,
|
|
percflowbelow,</literal> and <literal>pertypewithin</literal> are not
|
|
currently supported).</para>
|
|
|
|
<para>A "perthis" aspect is declared by specifying a
|
|
<literal>perthis</literal> clause in the
|
|
<interfacename>@Aspect</interfacename> annotation. Let's look at an
|
|
example, and then we'll explain how it works.</para>
|
|
|
|
<programlisting language="java">@Aspect("perthis(com.xyz.myapp.SystemArchitecture.businessService())")
|
|
public class MyAspect {
|
|
|
|
private int someState;
|
|
|
|
@Before(com.xyz.myapp.SystemArchitecture.businessService())
|
|
public void recordServiceUsage() {
|
|
<lineannotation>// ...</lineannotation>
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>The effect of the <literal>'perthis'</literal> clause is that one
|
|
aspect instance will be created for each unique service object executing
|
|
a business service (each unique object bound to 'this' at join points
|
|
matched by the pointcut expression). The aspect instance is created the
|
|
first time that a method is invoked on the service object. The aspect
|
|
goes out of scope when the service object goes out of scope. Before the
|
|
aspect instance is created, none of the advice within it executes. As
|
|
soon as the aspect instance has been created, the advice declared within
|
|
it will execute at matched join points, but only when the service object
|
|
is the one this aspect is associated with. See the AspectJ programming
|
|
guide for more information on per-clauses.</para>
|
|
|
|
<para>The <literal>'pertarget'</literal> instantiation model works in
|
|
exactly the same way as perthis, but creates one aspect instance for
|
|
each unique target object at matched join points.</para>
|
|
</section>
|
|
|
|
<section id="aop-ataspectj-example">
|
|
<title>Example</title>
|
|
|
|
<para>Now that you have seen how all the constituent parts work, let's
|
|
put them together to do something useful!</para>
|
|
|
|
<para>The execution of business services can sometimes fail due to
|
|
concurrency issues (for example, deadlock loser). If the operation is
|
|
retried, it is quite likely to succeed next time round. For business
|
|
services where it is appropriate to retry in such conditions (idempotent
|
|
operations that don't need to go back to the user for conflict
|
|
resolution), we'd like to transparently retry the operation to avoid the
|
|
client seeing a
|
|
<classname>PessimisticLockingFailureException</classname>. This is a
|
|
requirement that clearly cuts across multiple services in the service
|
|
layer, and hence is ideal for implementing via an aspect.</para>
|
|
|
|
<para>Because we want to retry the operation, we will need to use around
|
|
advice so that we can call proceed multiple times. Here's how the basic
|
|
aspect implementation looks:</para>
|
|
|
|
<programlisting language="java">@Aspect
|
|
public class ConcurrentOperationExecutor implements Ordered {
|
|
|
|
private static final int DEFAULT_MAX_RETRIES = 2;
|
|
|
|
private int maxRetries = DEFAULT_MAX_RETRIES;
|
|
private int order = 1;
|
|
|
|
public void setMaxRetries(int maxRetries) {
|
|
this.maxRetries = maxRetries;
|
|
}
|
|
|
|
public int getOrder() {
|
|
return this.order;
|
|
}
|
|
|
|
public void setOrder(int order) {
|
|
this.order = order;
|
|
}
|
|
|
|
@Around("com.xyz.myapp.SystemArchitecture.businessService()")
|
|
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
|
|
int numAttempts = 0;
|
|
PessimisticLockingFailureException lockFailureException;
|
|
do {
|
|
numAttempts++;
|
|
try {
|
|
return pjp.proceed();
|
|
}
|
|
catch(PessimisticLockingFailureException ex) {
|
|
lockFailureException = ex;
|
|
}
|
|
}
|
|
while(numAttempts <= this.maxRetries);
|
|
throw lockFailureException;
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>Note that the aspect implements the
|
|
<interfacename>Ordered</interfacename> interface so we can set the
|
|
precedence of the aspect higher than the transaction advice (we want a
|
|
fresh transaction each time we retry). The <literal>maxRetries</literal>
|
|
and <literal>order</literal> properties will both be configured by
|
|
Spring. The main action happens in the
|
|
<literal>doConcurrentOperation</literal> around advice. Notice that for
|
|
the moment we're applying the retry logic to all
|
|
<literal>businessService()s</literal>. We try to proceed, and if we fail
|
|
with an <classname>PessimisticLockingFailureException</classname> we
|
|
simply try again unless we have exhausted all of our retry
|
|
attempts.</para>
|
|
|
|
<para>The corresponding Spring configuration is:</para>
|
|
|
|
<programlisting language="xml"><aop:aspectj-autoproxy/>
|
|
|
|
<bean id="concurrentOperationExecutor"
|
|
class="com.xyz.myapp.service.impl.ConcurrentOperationExecutor">
|
|
<property name="maxRetries" value="3"/>
|
|
<property name="order" value="100"/>
|
|
</bean></programlisting>
|
|
|
|
<para>To refine the aspect so that it only retries idempotent
|
|
operations, we might define an <interfacename>Idempotent</interfacename>
|
|
annotation:</para>
|
|
|
|
<programlisting language="java">@Retention(RetentionPolicy.RUNTIME)
|
|
public @interface Idempotent {
|
|
<lineannotation>// marker annotation</lineannotation>
|
|
}</programlisting>
|
|
|
|
<para>and use the annotation to annotate the implementation of service
|
|
operations. The change to the aspect to only retry idempotent operations
|
|
simply involves refining the pointcut expression so that only
|
|
<interfacename>@Idempotent</interfacename> operations match:</para>
|
|
|
|
<programlisting language="java">@Around("com.xyz.myapp.SystemArchitecture.businessService() && " +
|
|
"@annotation(com.xyz.myapp.service.Idempotent)")
|
|
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
|
|
...
|
|
}</programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="aop-schema">
|
|
<title>Schema-based AOP support</title>
|
|
|
|
<para>If you are unable to use Java 5, or simply prefer an XML-based
|
|
format, then Spring 2.0 also offers support for defining aspects using the
|
|
new "aop" namespace tags. The exact same pointcut expressions and advice
|
|
kinds are supported as when using the @AspectJ style, hence in this
|
|
section we will focus on the new <emphasis>syntax</emphasis> and refer the
|
|
reader to the discussion in the previous section (<xref
|
|
linkend="aop-ataspectj" />) for an understanding of writing pointcut
|
|
expressions and the binding of advice parameters.</para>
|
|
|
|
<para>To use the aop namespace tags described in this section, you need to
|
|
import the spring-aop schema as described in <xref
|
|
linkend="xsd-config" />. See <xref
|
|
linkend="xsd-config-body-schemas-aop" /> for how to import the tags in the
|
|
aop namespace.</para>
|
|
|
|
<para>Within your Spring configurations, all aspect and advisor elements
|
|
must be placed within an <literal><aop:config></literal> element
|
|
(you can have more than one <literal><aop:config></literal> element
|
|
in an application context configuration). An
|
|
<literal><aop:config></literal> element can contain pointcut,
|
|
advisor, and aspect elements (note these must be declared in that
|
|
order).</para>
|
|
|
|
<warning>
|
|
<para>The <literal><aop:config></literal> style of configuration
|
|
makes heavy use of Spring's <link
|
|
linkend="aop-autoproxy">auto-proxying</link> mechanism. This can cause
|
|
issues (such as advice not being woven) if you are already using
|
|
explicit auto-proxying via the use of
|
|
<classname>BeanNameAutoProxyCreator</classname> or suchlike. The
|
|
recommended usage pattern is to use either just the
|
|
<literal><aop:config></literal> style, or just the
|
|
<interfacename>AutoProxyCreator</interfacename> style.</para>
|
|
</warning>
|
|
|
|
<section id="aop-schema-declaring-an-aspect">
|
|
<title>Declaring an aspect</title>
|
|
|
|
<para>Using the schema support, an aspect is simply a regular Java
|
|
object defined as a bean in your Spring application context. The state
|
|
and behavior is captured in the fields and methods of the object, and
|
|
the pointcut and advice information is captured in the XML.</para>
|
|
|
|
<para>An aspect is declared using the <aop:aspect> element, and
|
|
the backing bean is referenced using the <literal>ref</literal>
|
|
attribute:</para>
|
|
|
|
<programlisting language="xml"><aop:config>
|
|
<aop:aspect id="myAspect" ref="aBean">
|
|
...
|
|
</aop:aspect>
|
|
</aop:config>
|
|
|
|
<bean id="aBean" class="...">
|
|
...
|
|
</bean></programlisting>
|
|
|
|
<para>The bean backing the aspect ("<literal>aBean</literal>" in this
|
|
case) can of course be configured and dependency injected just like any
|
|
other Spring bean.</para>
|
|
</section>
|
|
|
|
<section id="aop-schema-pointcuts">
|
|
<title>Declaring a pointcut</title>
|
|
|
|
<para>A named pointcut can be declared inside an <aop:config>
|
|
element, enabling the pointcut definition to be shared across several
|
|
aspects and advisors.</para>
|
|
|
|
<para>A pointcut representing the execution of any business service in
|
|
the service layer could be defined as follows:</para>
|
|
|
|
<programlisting language="xml"><aop:config>
|
|
|
|
<aop:pointcut id="businessService"
|
|
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
|
|
|
|
</aop:config></programlisting>
|
|
|
|
<para>Note that the pointcut expression itself is using the same AspectJ
|
|
pointcut expression language as described in <xref
|
|
linkend="aop-ataspectj" />. If you are using the schema based
|
|
declaration style with Java 5, you can refer to named pointcuts defined
|
|
in types (@Aspects) within the pointcut expression, but this feature is
|
|
not available on JDK 1.4 and below (it relies on the Java 5 specific
|
|
AspectJ reflection APIs). On JDK 1.5 therefore, another way of defining
|
|
the above pointcut would be:</para>
|
|
|
|
<programlisting language="xml"><aop:config>
|
|
|
|
<aop:pointcut id="businessService"
|
|
expression="com.xyz.myapp.SystemArchitecture.businessService()"/>
|
|
|
|
</aop:config></programlisting>
|
|
|
|
<para>Assuming you have a <literal>SystemArchitecture</literal> aspect
|
|
as described in <xref linkend="aop-common-pointcuts" />.</para>
|
|
|
|
<para>Declaring a pointcut inside an aspect is very similar to declaring
|
|
a top-level pointcut:</para>
|
|
|
|
<programlisting language="xml"><aop:config>
|
|
|
|
<aop:aspect id="myAspect" ref="aBean">
|
|
|
|
<aop:pointcut id="businessService"
|
|
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
|
|
|
|
...
|
|
|
|
</aop:aspect>
|
|
|
|
</aop:config></programlisting>
|
|
|
|
<para>Much the same way in an @AspectJ aspect, pointcuts declared using
|
|
the schema based definition style may collect join point context. For
|
|
example, the following pointcut collects the 'this' object as the join
|
|
point context and passes it to advice:</para>
|
|
|
|
<programlisting language="xml"><aop:config>
|
|
|
|
<aop:aspect id="myAspect" ref="aBean">
|
|
|
|
<aop:pointcut id="businessService"
|
|
expression="execution(* com.xyz.myapp.service.*.*(..)) &amp;&amp; this(service)"/>
|
|
<aop:before pointcut-ref="businessService" method="monitor"/>
|
|
...
|
|
|
|
</aop:aspect>
|
|
|
|
</aop:config></programlisting>
|
|
|
|
<para>The advice must be declared to receive the collected join point
|
|
context by including parameters of the matching names:</para>
|
|
|
|
<programlisting language="java">public void monitor(Object service) {
|
|
...
|
|
}</programlisting>
|
|
|
|
<para>When combining pointcut sub-expressions, '&&' is awkward
|
|
within an XML document, and so the keywords 'and', 'or' and 'not' can be
|
|
used in place of '&&', '||' and '!' respectively. For example,
|
|
the previous pointcut may be better written as:</para>
|
|
|
|
<programlisting language="xml"><aop:config>
|
|
|
|
<aop:aspect id="myAspect" ref="aBean">
|
|
|
|
<aop:pointcut id="businessService"
|
|
expression="execution(* com.xyz.myapp.service.*.*(..)) <emphasis
|
|
role="bold">and</emphasis> this(service)"/>
|
|
<aop:before pointcut-ref="businessService" method="monitor"/>
|
|
...
|
|
|
|
</aop:aspect>
|
|
|
|
</aop:config></programlisting>
|
|
|
|
<para>Note that pointcuts defined in this way are referred to by their
|
|
XML id and cannot be used as named pointcuts to form composite
|
|
pointcuts. The named pointcut support in the schema based definition
|
|
style is thus more limited than that offered by the @AspectJ
|
|
style.</para>
|
|
</section>
|
|
|
|
<section id="aop-schema-advice">
|
|
<title>Declaring advice</title>
|
|
|
|
<para>The same five advice kinds are supported as for the @AspectJ
|
|
style, and they have exactly the same semantics.</para>
|
|
|
|
<section id="aop-schema-advice-before">
|
|
<title>Before advice</title>
|
|
|
|
<para>Before advice runs before a matched method execution. It is
|
|
declared inside an <literal><aop:aspect></literal> using the
|
|
<aop:before> element.</para>
|
|
|
|
<programlisting language="xml"><aop:aspect id="beforeExample" ref="aBean">
|
|
|
|
<aop:before
|
|
pointcut-ref="dataAccessOperation"
|
|
method="doAccessCheck"/>
|
|
|
|
...
|
|
|
|
</aop:aspect></programlisting>
|
|
|
|
<para>Here <literal>dataAccessOperation</literal> is the id of a
|
|
pointcut defined at the top (<literal><aop:config></literal>)
|
|
level. To define the pointcut inline instead, replace the
|
|
<literal>pointcut-ref</literal> attribute with a
|
|
<literal>pointcut</literal> attribute:</para>
|
|
|
|
<programlisting language="xml"><aop:aspect id="beforeExample" ref="aBean">
|
|
|
|
<aop:before
|
|
pointcut="execution(* com.xyz.myapp.dao.*.*(..))"
|
|
method="doAccessCheck"/>
|
|
|
|
...
|
|
|
|
</aop:aspect></programlisting>
|
|
|
|
<para>As we noted in the discussion of the @AspectJ style, using named
|
|
pointcuts can significantly improve the readability of your
|
|
code.</para>
|
|
|
|
<para>The method attribute identifies a method
|
|
(<literal>doAccessCheck</literal>) that provides the body of the
|
|
advice. This method must be defined for the bean referenced by the
|
|
aspect element containing the advice. Before a data access operation
|
|
is executed (a method execution join point matched by the pointcut
|
|
expression), the "doAccessCheck" method on the aspect bean will be
|
|
invoked.</para>
|
|
</section>
|
|
|
|
<section id="aop-schema-advice-after-returning">
|
|
<title>After returning advice</title>
|
|
|
|
<para>After returning advice runs when a matched method execution
|
|
completes normally. It is declared inside an
|
|
<literal><aop:aspect></literal> in the same way as before
|
|
advice. For example:</para>
|
|
|
|
<programlisting language="xml"><aop:aspect id="afterReturningExample" ref="aBean">
|
|
|
|
<aop:after-returning
|
|
pointcut-ref="dataAccessOperation"
|
|
method="doAccessCheck"/>
|
|
|
|
...
|
|
|
|
</aop:aspect></programlisting>
|
|
|
|
<para>Just as in the @AspectJ style, it is possible to get hold of the
|
|
return value within the advice body. Use the returning attribute to
|
|
specify the name of the parameter to which the return value should be
|
|
passed:</para>
|
|
|
|
<programlisting language="xml"><aop:aspect id="afterReturningExample" ref="aBean">
|
|
|
|
<aop:after-returning
|
|
pointcut-ref="dataAccessOperation"
|
|
returning="retVal"
|
|
method="doAccessCheck"/>
|
|
|
|
...
|
|
|
|
</aop:aspect></programlisting>
|
|
|
|
<para>The doAccessCheck method must declare a parameter named
|
|
<literal>retVal</literal>. The type of this parameter constrains
|
|
matching in the same way as described for @AfterReturning. For
|
|
example, the method signature may be declared as:</para>
|
|
|
|
<programlisting language="java">public void doAccessCheck(Object retVal) {...</programlisting>
|
|
</section>
|
|
|
|
<section id="aop-schema-advice-after-throwing">
|
|
<title>After throwing advice</title>
|
|
|
|
<para>After throwing advice executes when a matched method execution
|
|
exits by throwing an exception. It is declared inside an
|
|
<literal><aop:aspect></literal> using the after-throwing
|
|
element:</para>
|
|
|
|
<programlisting language="xml"><aop:aspect id="afterThrowingExample" ref="aBean">
|
|
|
|
<aop:after-throwing
|
|
pointcut-ref="dataAccessOperation"
|
|
method="doRecoveryActions"/>
|
|
|
|
...
|
|
|
|
</aop:aspect></programlisting>
|
|
|
|
<para>Just as in the @AspectJ style, it is possible to get hold of the
|
|
thrown exception within the advice body. Use the throwing attribute to
|
|
specify the name of the parameter to which the exception should be
|
|
passed:</para>
|
|
|
|
<programlisting language="xml"><aop:aspect id="afterThrowingExample" ref="aBean">
|
|
|
|
<aop:after-throwing
|
|
pointcut-ref="dataAccessOperation"
|
|
throwing="dataAccessEx"
|
|
method="doRecoveryActions"/>
|
|
|
|
...
|
|
|
|
</aop:aspect></programlisting>
|
|
|
|
<para>The doRecoveryActions method must declare a parameter named
|
|
<literal>dataAccessEx</literal>. The type of this parameter constrains
|
|
matching in the same way as described for @AfterThrowing. For example,
|
|
the method signature may be declared as:</para>
|
|
|
|
<programlisting language="java">public void doRecoveryActions(DataAccessException dataAccessEx) {...</programlisting>
|
|
</section>
|
|
|
|
<section id="aop-schema-advice-after-finally">
|
|
<title>After (finally) advice</title>
|
|
|
|
<para>After (finally) advice runs however a matched method execution
|
|
exits. It is declared using the <literal>after</literal>
|
|
element:</para>
|
|
|
|
<programlisting language="xml"><aop:aspect id="afterFinallyExample" ref="aBean">
|
|
|
|
<aop:after
|
|
pointcut-ref="dataAccessOperation"
|
|
method="doReleaseLock"/>
|
|
|
|
...
|
|
|
|
</aop:aspect></programlisting>
|
|
</section>
|
|
|
|
<section id="aop-schema-advice-around">
|
|
<title>Around advice</title>
|
|
|
|
<para>The final kind of advice is around advice. Around advice runs
|
|
"around" a matched method execution. It has the opportunity to do work
|
|
both before and after the method executes, and to determine when, how,
|
|
and even if, the method actually gets to execute at all. Around advice
|
|
is often used if you need to share state before and after a method
|
|
execution in a thread-safe manner (starting and stopping a timer for
|
|
example). Always use the least powerful form of advice that meets your
|
|
requirements; don't use around advice if simple before advice would
|
|
do.</para>
|
|
|
|
<para>Around advice is declared using the
|
|
<literal>aop:around</literal> element. The first parameter of the
|
|
advice method must be of type
|
|
<interfacename>ProceedingJoinPoint</interfacename>. Within the body of
|
|
the advice, calling <literal>proceed()</literal> on the
|
|
<interfacename>ProceedingJoinPoint</interfacename> causes the
|
|
underlying method to execute. The <literal>proceed</literal> method
|
|
may also be calling passing in an <classname>Object[]</classname> -
|
|
the values in the array will be used as the arguments to the method
|
|
execution when it proceeds. See <xref
|
|
linkend="aop-ataspectj-around-advice" /> for notes on calling proceed
|
|
with an <classname>Object[]</classname>.</para>
|
|
|
|
<programlisting language="xml"><aop:aspect id="aroundExample" ref="aBean">
|
|
|
|
<aop:around
|
|
pointcut-ref="businessService"
|
|
method="doBasicProfiling"/>
|
|
|
|
...
|
|
|
|
</aop:aspect></programlisting>
|
|
|
|
<para>The implementation of the <literal>doBasicProfiling</literal>
|
|
advice would be exactly the same as in the @AspectJ example (minus the
|
|
annotation of course):</para>
|
|
|
|
<programlisting language="java">public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
|
|
<lineannotation>// start stopwatch</lineannotation>
|
|
Object retVal = pjp.proceed();
|
|
<lineannotation>// stop stopwatch</lineannotation>
|
|
return retVal;
|
|
}</programlisting>
|
|
</section>
|
|
|
|
<section id="aop-schema-params">
|
|
<title>Advice parameters</title>
|
|
|
|
<para>The schema based declaration style supports fully typed advice
|
|
in the same way as described for the @AspectJ support - by matching
|
|
pointcut parameters by name against advice method parameters. See
|
|
<xref linkend="aop-ataspectj-advice-params" /> for details. If you
|
|
wish to explicitly specify argument names for the advice methods (not
|
|
relying on the detection strategies previously described) then this is
|
|
done using the <literal>arg-names</literal> attribute of the advice
|
|
element, which is treated in the same manner to the "argNames"
|
|
attribute in an advice annotation as described in <xref
|
|
linkend="aop-ataspectj-advice-params-names" />. For example:</para>
|
|
|
|
<programlisting language="xml"><aop:before
|
|
pointcut="com.xyz.lib.Pointcuts.anyPublicMethod() and @annotation(auditable)"
|
|
method="audit"
|
|
arg-names="auditable"/></programlisting>
|
|
|
|
<para>The <literal>arg-names</literal> attribute accepts a
|
|
comma-delimited list of parameter names.</para>
|
|
|
|
<para>Find below a slightly more involved example of the XSD-based
|
|
approach that illustrates some around advice used in conjunction with
|
|
a number of strongly typed parameters.</para>
|
|
|
|
<programlisting language="java">package x.y.service;
|
|
|
|
public interface FooService {
|
|
|
|
Foo getFoo(String fooName, int age);
|
|
}
|
|
|
|
public class DefaultFooService implements FooService {
|
|
|
|
public Foo getFoo(String name, int age) {
|
|
return new Foo(name, age);
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Next up is the aspect. Notice the fact that the
|
|
<methodname>profile(..)</methodname> method accepts a number of
|
|
strongly-typed parameters, the first of which happens to be the join
|
|
point used to proceed with the method call: the presence of this
|
|
parameter is an indication that the
|
|
<methodname>profile(..)</methodname> is to be used as
|
|
<literal>around</literal> advice:</para>
|
|
|
|
<programlisting language="java">package x.y;
|
|
|
|
import org.aspectj.lang.ProceedingJoinPoint;
|
|
import org.springframework.util.StopWatch;
|
|
|
|
public class SimpleProfiler {
|
|
|
|
public Object profile(ProceedingJoinPoint call, String name, int age) throws Throwable {
|
|
StopWatch clock = new StopWatch(
|
|
"Profiling for '" + name + "' and '" + age + "'");
|
|
try {
|
|
clock.start(call.toShortString());
|
|
return call.proceed();
|
|
} finally {
|
|
clock.stop();
|
|
System.out.println(clock.prettyPrint());
|
|
}
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Finally, here is the XML configuration that is required to
|
|
effect the execution of the above advice for a particular join
|
|
point:</para>
|
|
|
|
<programlisting language="xml"><beans xmlns="http://www.springframework.org/schema/beans"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xmlns:aop="http://www.springframework.org/schema/aop"
|
|
xsi:schemaLocation="
|
|
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
|
|
|
|
<lineannotation><!-- this is the object that will be proxied by Spring's AOP infrastructure --></lineannotation>
|
|
<bean id="fooService" class="x.y.service.DefaultFooService"/>
|
|
|
|
<lineannotation><!-- this is the actual advice itself --></lineannotation>
|
|
<bean id="profiler" class="x.y.SimpleProfiler"/>
|
|
|
|
<aop:config>
|
|
<aop:aspect ref="profiler">
|
|
|
|
<aop:pointcut id="theExecutionOfSomeFooServiceMethod"
|
|
expression="execution(* x.y.service.FooService.getFoo(String,int))
|
|
and args(name, age)"/>
|
|
|
|
<aop:around pointcut-ref="theExecutionOfSomeFooServiceMethod"
|
|
method="profile"/>
|
|
|
|
</aop:aspect>
|
|
</aop:config>
|
|
|
|
</beans></programlisting>
|
|
|
|
<para>If we had the following driver script, we would get output
|
|
something like this on standard output:</para>
|
|
|
|
<programlisting language="java">import org.springframework.beans.factory.BeanFactory;
|
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|
import x.y.service.FooService;
|
|
|
|
public final class Boot {
|
|
|
|
public static void main(final String[] args) throws Exception {
|
|
BeanFactory ctx = new ClassPathXmlApplicationContext("x/y/plain.xml");
|
|
FooService foo = (FooService) ctx.getBean("fooService");
|
|
foo.getFoo("Pengo", 12);
|
|
}
|
|
}</programlisting>
|
|
|
|
<programlisting>StopWatch 'Profiling for 'Pengo' and '12'': running time (millis) = 0
|
|
-----------------------------------------
|
|
ms % Task name
|
|
-----------------------------------------
|
|
00000 ? execution(getFoo)</programlisting>
|
|
</section>
|
|
|
|
<section id="aop-ordering">
|
|
<title>Advice ordering</title>
|
|
|
|
<para>When multiple advice needs to execute at the same join point
|
|
(executing method) the ordering rules are as described in <xref
|
|
linkend="aop-ataspectj-advice-ordering" />. The precedence between
|
|
aspects is determined by either adding the
|
|
<interfacename>Order</interfacename> annotation to the bean backing
|
|
the aspect or by having the bean implement the
|
|
<interfacename>Ordered</interfacename> interface.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="aop-schema-introductions">
|
|
<title>Introductions</title>
|
|
|
|
<para>Introductions (known as inter-type declarations in AspectJ) enable
|
|
an aspect to declare that advised objects implement a given interface,
|
|
and to provide an implementation of that interface on behalf of those
|
|
objects.</para>
|
|
|
|
<para>An introduction is made using the
|
|
<literal>aop:declare-parents</literal> element inside an
|
|
<literal>aop:aspect</literal> This element is used to declare that
|
|
matching types have a new parent (hence the name). For example, given an
|
|
interface <interfacename>UsageTracked</interfacename>, and an
|
|
implementation of that interface
|
|
<classname>DefaultUsageTracked</classname>, the following aspect
|
|
declares that all implementors of service interfaces also implement the
|
|
<interfacename>UsageTracked</interfacename> interface. (In order to
|
|
expose statistics via JMX for example.)</para>
|
|
|
|
<programlisting language="xml"><aop:aspect id="usageTrackerAspect" ref="usageTracking">
|
|
|
|
<aop:declare-parents
|
|
types-matching="com.xzy.myapp.service.*+"
|
|
implement-interface="com.xyz.myapp.service.tracking.UsageTracked"
|
|
default-impl="com.xyz.myapp.service.tracking.DefaultUsageTracked"/>
|
|
|
|
<aop:before
|
|
pointcut="com.xyz.myapp.SystemArchitecture.businessService()
|
|
and this(usageTracked)"
|
|
method="recordUsage"/>
|
|
|
|
</aop:aspect></programlisting>
|
|
|
|
<para>The class backing the <literal>usageTracking</literal> bean would
|
|
contain the method:</para>
|
|
|
|
<programlisting language="java">public void recordUsage(UsageTracked usageTracked) {
|
|
usageTracked.incrementUseCount();
|
|
}</programlisting>
|
|
|
|
<para>The interface to be implemented is determined by
|
|
<literal>implement-interface</literal> attribute. The value of the
|
|
<literal>types-matching</literal> attribute is an AspectJ type pattern
|
|
:- any bean of a matching type will implement the
|
|
<interfacename>UsageTracked</interfacename> interface. Note that in the
|
|
before advice of the above example, service beans can be directly used
|
|
as implementations of the <interfacename>UsageTracked</interfacename>
|
|
interface. If accessing a bean programmatically you would write the
|
|
following:</para>
|
|
|
|
<programlisting language="java">UsageTracked usageTracked = (UsageTracked) context.getBean("myService");</programlisting>
|
|
</section>
|
|
|
|
<section id="aop-schema-instatiation-models">
|
|
<title>Aspect instantiation models</title>
|
|
|
|
<para>The only supported instantiation model for schema-defined aspects
|
|
is the singleton model. Other instantiation models may be supported in
|
|
future releases.</para>
|
|
</section>
|
|
|
|
<section id="aop-schema-advisors">
|
|
<title>Advisors</title>
|
|
|
|
<para>The concept of "advisors" is brought forward from the AOP support
|
|
defined in Spring 1.2 and does not have a direct equivalent in AspectJ.
|
|
An advisor is like a small self-contained aspect that has a single piece
|
|
of advice. The advice itself is represented by a bean, and must
|
|
implement one of the advice interfaces described in <xref
|
|
linkend="aop-api-advice-types" />. Advisors can take advantage of
|
|
AspectJ pointcut expressions though.</para>
|
|
|
|
<para>Spring 2.0 supports the advisor concept with the
|
|
<literal><aop:advisor></literal> element. You will most commonly
|
|
see it used in conjunction with transactional advice, which also has its
|
|
own namespace support in Spring 2.0. Here's how it looks:</para>
|
|
|
|
<programlisting language="xml"><aop:config>
|
|
|
|
<aop:pointcut id="businessService"
|
|
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
|
|
|
|
<aop:advisor
|
|
pointcut-ref="businessService"
|
|
advice-ref="tx-advice"/>
|
|
|
|
</aop:config>
|
|
|
|
<tx:advice id="tx-advice">
|
|
<tx:attributes>
|
|
<tx:method name="*" propagation="REQUIRED"/>
|
|
</tx:attributes>
|
|
</tx:advice></programlisting>
|
|
</section>
|
|
|
|
<para>As well as the <literal>pointcut-ref</literal> attribute used in the
|
|
above example, you can also use the <literal>pointcut</literal> attribute
|
|
to define a pointcut expression inline.</para>
|
|
|
|
<para>To define the precedence of an advisor so that the advice can
|
|
participate in ordering, use the <literal>order</literal> attribute to
|
|
define the <literal>Ordered</literal> value of the advisor.</para>
|
|
|
|
<section id="aop-schema-example">
|
|
<title>Example</title>
|
|
|
|
<para>Let's see how the concurrent locking failure retry example from
|
|
<xref linkend="aop-ataspectj-example" /> looks when rewritten using the
|
|
schema support.</para>
|
|
|
|
<para>The execution of business services can sometimes fail due to
|
|
concurrency issues (for example, deadlock loser). If the operation is
|
|
retried, it is quite likely it will succeed next time round. For
|
|
business services where it is appropriate to retry in such conditions
|
|
(idempotent operations that don't need to go back to the user for
|
|
conflict resolution), we'd like to transparently retry the operation to
|
|
avoid the client seeing a
|
|
<classname>PessimisticLockingFailureException</classname>. This is a
|
|
requirement that clearly cuts across multiple services in the service
|
|
layer, and hence is ideal for implementing via an aspect.</para>
|
|
|
|
<para>Because we want to retry the operation, we'll need to use around
|
|
advice so that we can call proceed multiple times. Here's how the basic
|
|
aspect implementation looks (it's just a regular Java class using the
|
|
schema support):</para>
|
|
|
|
<programlisting language="java">public class ConcurrentOperationExecutor implements Ordered {
|
|
|
|
private static final int DEFAULT_MAX_RETRIES = 2;
|
|
|
|
private int maxRetries = DEFAULT_MAX_RETRIES;
|
|
private int order = 1;
|
|
|
|
public void setMaxRetries(int maxRetries) {
|
|
this.maxRetries = maxRetries;
|
|
}
|
|
|
|
public int getOrder() {
|
|
return this.order;
|
|
}
|
|
|
|
public void setOrder(int order) {
|
|
this.order = order;
|
|
}
|
|
|
|
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
|
|
int numAttempts = 0;
|
|
PessimisticLockingFailureException lockFailureException;
|
|
do {
|
|
numAttempts++;
|
|
try {
|
|
return pjp.proceed();
|
|
}
|
|
catch(PessimisticLockingFailureException ex) {
|
|
lockFailureException = ex;
|
|
}
|
|
}
|
|
while(numAttempts <= this.maxRetries);
|
|
throw lockFailureException;
|
|
}
|
|
|
|
}</programlisting>
|
|
|
|
<para>Note that the aspect implements the
|
|
<interfacename>Ordered</interfacename> interface so we can set the
|
|
precedence of the aspect higher than the transaction advice (we want a
|
|
fresh transaction each time we retry). The <literal>maxRetries</literal>
|
|
and <literal>order</literal> properties will both be configured by
|
|
Spring. The main action happens in the
|
|
<literal>doConcurrentOperation</literal> around advice method. We try to
|
|
proceed, and if we fail with a
|
|
<classname>PessimisticLockingFailureException</classname> we simply try
|
|
again unless we have exhausted all of our retry attempts.</para>
|
|
|
|
<remark>This class is identical to the one used in the @AspectJ example,
|
|
but with the annotations removed.</remark>
|
|
|
|
<para>The corresponding Spring configuration is:</para>
|
|
|
|
<programlisting language="xml"><aop:config>
|
|
|
|
<aop:aspect id="concurrentOperationRetry" ref="concurrentOperationExecutor">
|
|
|
|
<aop:pointcut id="idempotentOperation"
|
|
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
|
|
|
|
<aop:around
|
|
pointcut-ref="idempotentOperation"
|
|
method="doConcurrentOperation"/>
|
|
|
|
</aop:aspect>
|
|
|
|
</aop:config>
|
|
|
|
<bean id="concurrentOperationExecutor"
|
|
class="com.xyz.myapp.service.impl.ConcurrentOperationExecutor">
|
|
<property name="maxRetries" value="3"/>
|
|
<property name="order" value="100"/>
|
|
</bean></programlisting>
|
|
|
|
<para>Notice that for the time being we assume that all business
|
|
services are idempotent. If this is not the case we can refine the
|
|
aspect so that it only retries genuinely idempotent operations, by
|
|
introducing an <interfacename>Idempotent</interfacename>
|
|
annotation:</para>
|
|
|
|
<programlisting language="java">@Retention(RetentionPolicy.RUNTIME)
|
|
public @interface Idempotent {
|
|
<lineannotation>// marker annotation</lineannotation>
|
|
}</programlisting>
|
|
|
|
<para>and using the annotation to annotate the implementation of service
|
|
operations. The change to the aspect to retry only idempotent operations
|
|
simply involves refining the pointcut expression so that only
|
|
<interfacename>@Idempotent</interfacename> operations match:</para>
|
|
|
|
<programlisting language="xml"> <aop:pointcut id="idempotentOperation"
|
|
expression="execution(* com.xyz.myapp.service.*.*(..)) and
|
|
@annotation(com.xyz.myapp.service.Idempotent)"/></programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="aop-choosing">
|
|
<title>Choosing which AOP declaration style to use</title>
|
|
|
|
<para>Once you have decided that an aspect is the best approach for
|
|
implementing a given requirement, how do you decide between using Spring
|
|
AOP or AspectJ, and between the Aspect language (code) style, @AspectJ
|
|
annotation style, or the Spring XML style? These decisions are influenced
|
|
by a number of factors including application requirements, development
|
|
tools, and team familiarity with AOP.</para>
|
|
|
|
<section id="aop-spring-or-aspectj">
|
|
<title>Spring AOP or full AspectJ?</title>
|
|
|
|
<para>Use the simplest thing that can work. Spring AOP is simpler than
|
|
using full AspectJ as there is no requirement to introduce the AspectJ
|
|
compiler / weaver into your development and build processes. If you only
|
|
need to advise the execution of operations on Spring beans, then Spring
|
|
AOP is the right choice. If you need to advise objects not managed by
|
|
the Spring container (such as domain objects typically), then you will
|
|
need to use AspectJ. You will also need to use AspectJ if you wish to
|
|
advise join points other than simple method executions (for example,
|
|
field get or set join points, and so on).</para>
|
|
|
|
<para>When using AspectJ, you have the choice of the AspectJ language
|
|
syntax (also known as the "code style") or the @AspectJ annotation
|
|
style. Clearly, if you are not using Java 5+ then the choice has been
|
|
made for you... use the code style. If aspects play a large role in your
|
|
design, and you are able to use the <ulink
|
|
url="http://www.eclipse.org/ajdt/">AspectJ Development Tools
|
|
(AJDT)</ulink> plugin for Eclipse, then the AspectJ language syntax is
|
|
the preferred option: it is cleaner and simpler because the language was
|
|
purposefully designed for writing aspects. If you are not using Eclipse,
|
|
or have only a few aspects that do not play a major role in your
|
|
application, then you may want to consider using the @AspectJ style and
|
|
sticking with a regular Java compilation in your IDE, and adding an
|
|
aspect weaving phase to your build script.</para>
|
|
</section>
|
|
|
|
<section id="aop-ataspectj-or-xml">
|
|
<title>@AspectJ or XML for Spring AOP?</title>
|
|
|
|
<para>If you have chosen to use Spring AOP, then you have a choice of
|
|
@AspectJ or XML style. Clearly if you are not running on Java 5+, then
|
|
the XML style is the appropriate choice; for Java 5 projects there are
|
|
various tradeoffs to consider.</para>
|
|
|
|
<para>The XML style will be most familiar to existing Spring users. It
|
|
can be used with any JDK level (referring to named pointcuts from within
|
|
pointcut expressions does still require Java 5+ though) and is backed by
|
|
genuine POJOs. When using AOP as a tool to configure enterprise services
|
|
then XML can be a good choice (a good test is whether you consider the
|
|
pointcut expression to be a part of your configuration you might want to
|
|
change independently). With the XML style arguably it is clearer from
|
|
your configuration what aspects are present in the system.</para>
|
|
|
|
<para>The XML style has two disadvantages. Firstly it does not fully
|
|
encapsulate the implementation of the requirement it addresses in a
|
|
single place. The DRY principle says that there should be a single,
|
|
unambiguous, authoritative representation of any piece of knowledge
|
|
within a system. When using the XML style, the knowledge of
|
|
<emphasis>how</emphasis> a requirement is implemented is split across
|
|
the declaration of the backing bean class, and the XML in the
|
|
configuration file. When using the @AspectJ style there is a single
|
|
module - the aspect - in which this information is encapsulated.
|
|
Secondly, the XML style is slightly more limited in what it can express
|
|
than the @AspectJ style: only the "singleton" aspect instantiation model
|
|
is supported, and it is not possible to combine named pointcuts declared
|
|
in XML. For example, in the @AspectJ style you can write something
|
|
like:</para>
|
|
|
|
<programlisting language="java"> @Pointcut(execution(* get*()))
|
|
public void propertyAccess() {}
|
|
|
|
@Pointcut(execution(org.xyz.Account+ *(..))
|
|
public void operationReturningAnAccount() {}
|
|
|
|
@Pointcut(propertyAccess() && operationReturningAnAccount())
|
|
public void accountPropertyAccess() {}</programlisting>
|
|
|
|
<para>In the XML style I can declare the first two pointcuts:</para>
|
|
|
|
<programlisting language="xml"> <aop:pointcut id="propertyAccess"
|
|
expression="execution(* get*())"/>
|
|
|
|
<aop:pointcut id="operationReturningAnAccount"
|
|
expression="execution(org.xyz.Account+ *(..))"/></programlisting>
|
|
|
|
<para>The downside of the XML approach is that you cannot define the
|
|
'<literal>accountPropertyAccess</literal>' pointcut by combining these
|
|
definitions.</para>
|
|
|
|
<para>The @AspectJ style supports additional instantiation models, and
|
|
richer pointcut composition. It has the advantage of keeping the aspect
|
|
as a modular unit. It also has the advantage the @AspectJ aspects can be
|
|
understood (and thus consumed) both by Spring AOP and by AspectJ - so if
|
|
you later decide you need the capabilities of AspectJ to implement
|
|
additional requirements then it is very easy to migrate to an
|
|
AspectJ-based approach. On balance the Spring team prefer the @AspectJ
|
|
style whenever you have aspects that do more than simple "configuration"
|
|
of enterprise services.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="aop-mixing-styles">
|
|
<title>Mixing aspect types</title>
|
|
|
|
<para>It is perfectly possible to mix @AspectJ style aspects using the
|
|
autoproxying support, schema-defined <literal><aop:aspect></literal>
|
|
aspects, <literal><aop:advisor></literal> declared advisors and even
|
|
proxies and interceptors defined using the Spring 1.2 style in the same
|
|
configuration. All of these are implemented using the same underlying
|
|
support mechanism and will co-exist without any difficulty.</para>
|
|
</section>
|
|
|
|
<section id="aop-proxying">
|
|
<title>Proxying mechanisms</title>
|
|
|
|
<para>Spring AOP uses either JDK dynamic proxies or CGLIB to create the
|
|
proxy for a given target object. (JDK dynamic proxies are preferred
|
|
whenever you have a choice).</para>
|
|
|
|
<para>If the target object to be proxied implements at least one interface
|
|
then a JDK dynamic proxy will be used. All of the interfaces implemented
|
|
by the target type will be proxied. If the target object does not
|
|
implement any interfaces then a CGLIB proxy will be created.</para>
|
|
|
|
<para>If you want to force the use of CGLIB proxying (for example, to
|
|
proxy every method defined for the target object, not just those
|
|
implemented by its interfaces) you can do so. However, there are some
|
|
issues to consider:</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><literal>final</literal> methods cannot be advised, as they
|
|
cannot be overriden.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>You will need the CGLIB 2 binaries on your classpath, whereas
|
|
dynamic proxies are available with the JDK. Spring will automatically
|
|
warn you when it needs CGLIB and the CGLIB library classes are not
|
|
found on the classpath.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>The constructor of your proxied object will be called twice.
|
|
This is a natural consequence of the CGLIB proxy model whereby a
|
|
subclass is generated for each proxied object. For each proxied
|
|
instance, two objects are created: the actual proxied object and an
|
|
instance of the subclass that implements the advice. This behavior is
|
|
not exhibited when using JDK proxies. Usually, calling the constructor
|
|
of the proxied type twice, is not an issue, as there are usually only
|
|
assignments taking place and no real logic is implemented in the
|
|
constructor.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
|
|
<para id="aop-autoproxy-force-CGLIB">To force the use of CGLIB proxies set
|
|
the value of the <literal>proxy-target-class</literal> attribute of the
|
|
<literal><aop:config></literal> element to true:</para>
|
|
|
|
<programlisting language="xml"><aop:config <emphasis role="bold">proxy-target-class="true"</emphasis>>
|
|
<lineannotation><!-- other beans defined here... --></lineannotation>
|
|
</aop:config></programlisting>
|
|
|
|
<para>To force CGLIB proxying when using the @AspectJ autoproxy support,
|
|
set the <literal>'proxy-target-class'</literal> attribute of the
|
|
<literal><aop:aspectj-autoproxy></literal> element to
|
|
<literal>true</literal>:</para>
|
|
|
|
<programlisting language="xml"><aop:aspectj-autoproxy <emphasis role="bold">proxy-target-class="true"</emphasis>/></programlisting>
|
|
|
|
<note>
|
|
<para>Multiple <literal><aop:config/></literal> sections are
|
|
collapsed into a single unified auto-proxy creator at runtime, which
|
|
applies the <emphasis>strongest</emphasis> proxy settings that any of
|
|
the <literal><aop:config/></literal> sections (typically from
|
|
different XML bean definition files) specified. This also applies to the
|
|
<literal><tx:annotation-driven/></literal> and
|
|
<literal><aop:aspectj-autoproxy/></literal> elements.</para>
|
|
|
|
<para>To be clear: using '<literal>proxy-target-class="true"</literal>'
|
|
on <literal><tx:annotation-driven/></literal>,
|
|
<literal><aop:aspectj-autoproxy/></literal> or
|
|
<literal><aop:config/></literal> elements will force the use of
|
|
CGLIB proxies <emphasis>for all three of them</emphasis>.</para>
|
|
</note>
|
|
|
|
<section id="aop-understanding-aop-proxies">
|
|
<title>Understanding AOP proxies</title>
|
|
|
|
<para>Spring AOP is <emphasis>proxy-based</emphasis>. It is vitally
|
|
important that you grasp the semantics of what that last statement
|
|
actually means before you write your own aspects or use any of the
|
|
Spring AOP-based aspects supplied with the Spring Framework.</para>
|
|
|
|
<para>Consider first the scenario where you have a plain-vanilla,
|
|
un-proxied, nothing-special-about-it, straight object reference, as
|
|
illustrated by the following code snippet.</para>
|
|
|
|
<programlisting language="java">public class SimplePojo implements Pojo {
|
|
|
|
public void foo() {
|
|
<lineannotation>// this next method invocation is a <emphasis
|
|
role="bold">direct</emphasis> call on the 'this' reference</lineannotation>
|
|
this.bar();
|
|
}
|
|
|
|
public void bar() {
|
|
<lineannotation>// some logic...</lineannotation>
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>If you invoke a method on an object reference, the method is
|
|
invoked <emphasis>directly</emphasis> on that object reference, as can
|
|
be seen below.</para>
|
|
|
|
<para><mediaobject>
|
|
<imageobject role="fo">
|
|
<imagedata align="center"
|
|
fileref="images/aop-proxy-plain-pojo-call.png"
|
|
format="PNG" />
|
|
</imageobject>
|
|
|
|
<imageobject role="html">
|
|
<imagedata align="center"
|
|
fileref="images/aop-proxy-plain-pojo-call.png"
|
|
format="PNG" />
|
|
</imageobject>
|
|
</mediaobject></para>
|
|
|
|
<programlisting language="java">public class Main {
|
|
|
|
public static void main(String[] args) {
|
|
|
|
Pojo pojo = new SimplePojo();
|
|
|
|
<lineannotation>// this is a <emphasis role="bold">direct</emphasis> method call on the 'pojo' reference</lineannotation>
|
|
pojo.foo();
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Things change slightly when the reference that client code has is
|
|
a proxy. Consider the following diagram and code snippet.</para>
|
|
|
|
<para><mediaobject>
|
|
<imageobject role="fo">
|
|
<imagedata align="center" fileref="images/aop-proxy-call.png"
|
|
format="PNG" />
|
|
</imageobject>
|
|
|
|
<imageobject role="html">
|
|
<imagedata align="center" fileref="images/aop-proxy-call.png"
|
|
format="PNG" />
|
|
</imageobject>
|
|
</mediaobject></para>
|
|
|
|
<programlisting language="java">public class Main {
|
|
|
|
public static void main(String[] args) {
|
|
|
|
ProxyFactory factory = new ProxyFactory(new SimplePojo());
|
|
factory.addInterface(Pojo.class);
|
|
factory.addAdvice(new RetryAdvice());
|
|
|
|
Pojo pojo = (Pojo) factory.getProxy();
|
|
|
|
<lineannotation>// this is a method call <emphasis role="bold">on the proxy!</emphasis></lineannotation>
|
|
pojo.foo();
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>The key thing to understand here is that the client code inside
|
|
the <methodname>main(..)</methodname> of the <classname>Main</classname>
|
|
class <emphasis>has a reference to the proxy</emphasis>. This means that
|
|
method calls on that object reference will be calls on the proxy, and as
|
|
such the proxy will be able to delegate to all of the interceptors
|
|
(advice) that are relevant to that particular method call. However, once
|
|
the call has finally reached the target object, the
|
|
<classname>SimplePojo</classname> reference in this case, any method
|
|
calls that it may make on itself, such as
|
|
<methodname>this.bar()</methodname> or
|
|
<methodname>this.foo()</methodname>, are going to be invoked against the
|
|
<emphasis><literal>this</literal></emphasis> reference, and
|
|
<emphasis>not</emphasis> the proxy. This has important implications. It
|
|
means that self-invocation is <emphasis>not</emphasis> going to result
|
|
in the advice associated with a method invocation getting a chance to
|
|
execute.</para>
|
|
|
|
<para>Okay, so what is to be done about this? The best approach (the
|
|
term best is used loosely here) is to refactor your code such that the
|
|
self-invocation does not happen. For sure, this does entail some work on
|
|
your part, but it is the best, least-invasive approach. The next
|
|
approach is absolutely horrendous, and I am almost reticent to point it
|
|
out precisely because it is so horrendous. You can (choke!) totally tie
|
|
the logic within your class to Spring AOP by doing this:</para>
|
|
|
|
<programlisting language="java">public class SimplePojo implements Pojo {
|
|
|
|
public void foo() {
|
|
<lineannotation>// this works, but... gah!</lineannotation>
|
|
((Pojo) AopContext.currentProxy()).bar();
|
|
}
|
|
|
|
public void bar() {
|
|
<lineannotation>// some logic...</lineannotation>
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>This totally couples your code to Spring AOP,
|
|
<emphasis>and</emphasis> it makes the class itself aware of the fact
|
|
that it is being used in an AOP context, which flies in the face of AOP.
|
|
It also requires some additional configuration when the proxy is being
|
|
created:</para>
|
|
|
|
<programlisting language="java">public class Main {
|
|
|
|
public static void main(String[] args) {
|
|
|
|
ProxyFactory factory = new ProxyFactory(new SimplePojo());
|
|
factory.adddInterface(Pojo.class);
|
|
factory.addAdvice(new RetryAdvice());
|
|
<lineannotation><emphasis role="bold">factory.setExposeProxy(true);</emphasis></lineannotation>
|
|
|
|
Pojo pojo = (Pojo) factory.getProxy();
|
|
|
|
<lineannotation>// this is a method call <emphasis role="bold">on the proxy!</emphasis></lineannotation>
|
|
pojo.foo();
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Finally, it must be noted that AspectJ does not have this
|
|
self-invocation issue because it is not a proxy-based AOP
|
|
framework.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="aop-aspectj-programmatic">
|
|
<title>Programmatic creation of @AspectJ Proxies</title>
|
|
|
|
<para>In addition to declaring aspects in your configuration using either
|
|
<literal><aop:config></literal> or
|
|
<literal><aop:aspectj-autoproxy></literal>, it is also possible
|
|
programmatically to create proxies that advise target objects. For the
|
|
full details of Spring's AOP API, see the next chapter. Here we want to
|
|
focus on the ability to automatically create proxies using @AspectJ
|
|
aspects.</para>
|
|
|
|
<para>The class
|
|
<classname>org.springframework.aop.aspectj.annotation.AspectJProxyFactory</classname>
|
|
can be used to create a proxy for a target object that is advised by one
|
|
or more @AspectJ aspects. Basic usage for this class is very simple, as
|
|
illustrated below. See the Javadocs for full information.</para>
|
|
|
|
<programlisting language="java"><lineannotation>// create a factory that can generate a proxy for the given target object</lineannotation>
|
|
AspectJProxyFactory factory = new AspectJProxyFactory(targetObject);
|
|
|
|
<lineannotation>// add an aspect, the class must be an @AspectJ aspect
|
|
// you can call this as many times as you need with different aspects</lineannotation>
|
|
factory.addAspect(SecurityManager.class);
|
|
|
|
<lineannotation>// you can also add existing aspect instances, the type of the object supplied must be an @AspectJ aspect</lineannotation>
|
|
factory.addAspect(usageTracker);
|
|
|
|
<lineannotation>// now get the proxy object...</lineannotation>
|
|
MyInterfaceType proxy = factory.getProxy();</programlisting>
|
|
</section>
|
|
|
|
<section id="aop-using-aspectj">
|
|
<title>Using AspectJ with Spring applications</title>
|
|
|
|
<para>Everything we've covered so far in this chapter is pure Spring AOP.
|
|
In this section, we're going to look at how you can use the AspectJ
|
|
compiler/weaver instead of, or in addition to, Spring AOP if your needs go
|
|
beyond the facilities offered by Spring AOP alone.</para>
|
|
|
|
<para>Spring ships with a small AspectJ aspect library, which is available
|
|
standalone in your distribution as <filename
|
|
class="libraryfile">spring-aspects.jar</filename>; you'll need to add this
|
|
to your classpath in order to use the aspects in it. <xref
|
|
linkend="aop-atconfigurable"/> and <xref linkend="aop-ajlib-other"/>
|
|
discuss the content of this library and how you can use it. <xref
|
|
linkend="aop-aj-configure"/> discusses how to dependency inject AspectJ
|
|
aspects that are woven using the AspectJ compiler. Finally, <xref
|
|
linkend="aop-aj-ltw"/> provides an introduction to load-time weaving for
|
|
Spring applications using AspectJ.</para>
|
|
|
|
<section id="aop-atconfigurable">
|
|
<title>Using AspectJ to dependency inject domain objects with
|
|
Spring</title>
|
|
|
|
<para>The Spring container instantiates and configures beans defined in
|
|
your application context. It is also possible to ask a bean factory to
|
|
configure a <emphasis>pre-existing</emphasis> object given the name of a
|
|
bean definition containing the configuration to be applied. The
|
|
<filename class="libraryfile">spring-aspects.jar</filename> contains an
|
|
annotation-driven aspect that exploits this capability to allow
|
|
dependency injection of <emphasis>any object</emphasis>. The support is
|
|
intended to be used for objects created <emphasis>outside of the control
|
|
of any container</emphasis>. Domain objects often fall into this
|
|
category because they are often created programmatically using the
|
|
<literal>new</literal> operator, or by an ORM tool as a result of a
|
|
database query.</para>
|
|
|
|
<para>The <interfacename>@Configurable</interfacename> annotation marks
|
|
a class as eligible for Spring-driven configuration. In the simplest
|
|
case it can be used just as a marker annotation:</para>
|
|
|
|
<programlisting language="java">package com.xyz.myapp.domain;
|
|
|
|
import org.springframework.beans.factory.annotation.Configurable;
|
|
|
|
@Configurable
|
|
public class Account {
|
|
<lineannotation>// ...</lineannotation>
|
|
}</programlisting>
|
|
|
|
<para>When used as a marker interface in this way, Spring will configure
|
|
new instances of the annotated type (<classname>Account</classname> in
|
|
this case) using a prototype-scoped bean definition with the same name
|
|
as the fully-qualified type name
|
|
(<classname>com.xyz.myapp.domain.Account</classname>). Since the default
|
|
name for a bean is the fully-qualified name of its type, a convenient
|
|
way to declare the prototype definition is simply to omit the
|
|
<literal>id</literal> attribute:</para>
|
|
|
|
<programlisting language="xml"><bean class="com.xyz.myapp.domain.Account" scope="prototype">
|
|
<property name="fundsTransferService" ref="fundsTransferService"/>
|
|
</bean></programlisting>
|
|
|
|
<para>If you want to explicitly specify the name of the prototype bean
|
|
definition to use, you can do so directly in the annotation:</para>
|
|
|
|
<programlisting language="java">package com.xyz.myapp.domain;
|
|
|
|
import org.springframework.beans.factory.annotation.Configurable;
|
|
|
|
@Configurable("account")
|
|
public class Account {
|
|
<lineannotation>// ...</lineannotation>
|
|
}</programlisting>
|
|
|
|
<para>Spring will now look for a bean definition named
|
|
"<literal>account</literal>" and use that as the definition to configure
|
|
new <classname>Account</classname> instances.</para>
|
|
|
|
<para>You can also use autowiring to avoid having to specify a
|
|
prototype-scoped bean definition at all. To have Spring apply autowiring
|
|
use the '<literal>autowire</literal>' property of the
|
|
<interfacename>@Configurable</interfacename> annotation: specify either
|
|
<literal>@Configurable(autowire=Autowire.BY_TYPE)</literal> or
|
|
<literal>@Configurable(autowire=Autowire.BY_NAME</literal> for
|
|
autowiring by type or by name respectively. As an alternative, as of
|
|
Spring 2.5 it is preferable to specify explicit, annotation-driven
|
|
dependency injection for your <interfacename>@Configurable</interfacename>
|
|
beans by using <interfacename>@Autowired</interfacename> and
|
|
<interfacename>@Resource</interfacename> at the field or method level (see
|
|
<xref linkend="beans-annotation-config" /> for further details).</para>
|
|
|
|
<para>Finally you can enable Spring dependency checking for the object
|
|
references in the newly created and configured object by using the
|
|
<literal>dependencyCheck</literal> attribute (for example:
|
|
<literal>@Configurable(autowire=Autowire.BY_NAME,dependencyCheck=true)</literal>).
|
|
If this attribute is set to true, then Spring will validate after
|
|
configuration that all properties (<emphasis>which are not primitives or
|
|
collections</emphasis>) have been set.</para>
|
|
|
|
<para>Using the annotation on its own does nothing of course. It is the
|
|
<classname>AnnotationBeanConfigurerAspect</classname> in <filename
|
|
class="libraryfile">spring-aspects.jar</filename> that acts on the
|
|
presence of the annotation. In essence the aspect says "after returning
|
|
from the initialization of a new object of a type annotated with
|
|
<interfacename>@Configurable</interfacename>, configure the newly
|
|
created object using Spring in accordance with the properties of the
|
|
annotation". In this context, <emphasis>initialization</emphasis> refers
|
|
to newly instantiated objects (e.g., objects instantiated with the
|
|
'<literal>new</literal>' operator) as well as to
|
|
<interfacename>Serializable</interfacename> objects that are undergoing
|
|
deserialization (e.g., via <ulink
|
|
url="http://java.sun.com/j2se/1.5.0/docs/api/java/io/Serializable.html">readResolve()</ulink>).</para>
|
|
|
|
<note>
|
|
<para>One of the key phrases in the above paragraph is '<emphasis>in
|
|
essence</emphasis>'. For most cases, the exact semantics of
|
|
'<emphasis>after returning from the initialization of a new
|
|
object</emphasis>' will be fine... in this context, '<emphasis>after
|
|
initialization</emphasis>' means that the dependencies will be
|
|
injected <emphasis>after</emphasis> the object has been constructed -
|
|
this means that the dependencies will not be available for use in the
|
|
constructor bodies of the class. If you want the dependencies to be
|
|
injected <emphasis>before</emphasis> the constructor bodies execute,
|
|
and thus be available for use in the body of the constructors, then
|
|
you need to define this on the
|
|
<interfacename>@Configurable</interfacename> declaration like
|
|
so:</para>
|
|
|
|
<programlisting language="java">@Configurable(preConstruction=true)</programlisting>
|
|
|
|
<para>You can find out more information about the language semantics
|
|
of the various pointcut types in AspectJ <ulink
|
|
url="http://www.eclipse.org/aspectj/doc/next/progguide/semantics-joinPoints.html">in
|
|
this appendix</ulink> of the <ulink
|
|
url="http://www.eclipse.org/aspectj/doc/next/progguide/index.html">AspectJ
|
|
Programming Guide</ulink>.</para>
|
|
</note>
|
|
|
|
<para>For this to work the annotated types must be woven with the
|
|
AspectJ weaver - you can either use a build-time Ant or Maven task to do
|
|
this (see for example the <ulink
|
|
url="http://www.eclipse.org/aspectj/doc/released/devguide/antTasks.html">AspectJ
|
|
Development Environment Guide</ulink>) or load-time weaving (see <xref
|
|
linkend="aop-aj-ltw"/>). The
|
|
<classname>AnnotationBeanConfigurerAspect</classname> itself needs
|
|
configuring by Spring (in order to obtain a reference to the bean
|
|
factory that is to be used to configure new objects). The Spring <link
|
|
linkend="xsd-config-body-schemas-context"><literal>context</literal>
|
|
namespace</link> defines a convenient tag for doing this: just include
|
|
the following in your application context configuration:</para>
|
|
|
|
<programlisting language="xml"><context:spring-configured/></programlisting>
|
|
|
|
<para>If you are using the DTD instead of schema, the equivalent
|
|
definition is:</para>
|
|
|
|
<programlisting language="xml"><bean
|
|
class="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect"
|
|
factory-method="aspectOf"/></programlisting>
|
|
|
|
<para>Instances of <interfacename>@Configurable</interfacename> objects
|
|
created <emphasis>before</emphasis> the aspect has been configured will
|
|
result in a warning being issued to the log and no configuration of the
|
|
object taking place. An example might be a bean in the Spring
|
|
configuration that creates domain objects when it is initialized by
|
|
Spring. In this case you can use the "depends-on" bean attribute to
|
|
manually specify that the bean depends on the configuration
|
|
aspect.</para>
|
|
|
|
<programlisting language="xml"><bean id="myService"
|
|
class="com.xzy.myapp.service.MyService"
|
|
depends-on="org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect">
|
|
|
|
<lineannotation><!-- ... --></lineannotation>
|
|
|
|
</bean></programlisting>
|
|
|
|
<section id="aop-configurable-testing">
|
|
<title>Unit testing <interfacename>@Configurable</interfacename>
|
|
objects</title>
|
|
|
|
<para>One of the goals of the
|
|
<interfacename>@Configurable</interfacename> support is to enable
|
|
independent unit testing of domain objects without the difficulties
|
|
associated with hard-coded lookups. If
|
|
<interfacename>@Configurable</interfacename> types have not been woven
|
|
by AspectJ then the annotation has no affect during unit testing, and
|
|
you can simply set mock or stub property references in the object
|
|
under test and proceed as normal. If
|
|
<interfacename>@Configurable</interfacename> types
|
|
<emphasis>have</emphasis> been woven by AspectJ then you can still
|
|
unit test outside of the container as normal, but you will see a
|
|
warning message each time that you construct an
|
|
<interfacename>@Configurable</interfacename> object indicating that it
|
|
has not been configured by Spring.</para>
|
|
</section>
|
|
|
|
<section id="aop-configurable-container">
|
|
<title>Working with multiple application contexts</title>
|
|
|
|
<para>The <classname>AnnotationBeanConfigurerAspect</classname> used
|
|
to implement the <interfacename>@Configurable</interfacename> support
|
|
is an AspectJ singleton aspect. The scope of a singleton aspect is the
|
|
same as the scope of <literal>static</literal> members, that is to say
|
|
there is one aspect instance per classloader that defines the type.
|
|
This means that if you define multiple application contexts within the
|
|
same classloader hierarchy you need to consider where to define the
|
|
<literal><context:spring-configured/></literal> bean and where to
|
|
place <filename class="libraryfile">spring-aspects.jar</filename> on
|
|
the classpath.</para>
|
|
|
|
<para>Consider a typical Spring web-app configuration with a shared
|
|
parent application context defining common business services and
|
|
everything needed to support them, and one child application context
|
|
per servlet containing definitions particular to that servlet. All of
|
|
these contexts will co-exist within the same classloader hierarchy,
|
|
and so the <literal>AnnotationBeanConfigurerAspect</literal> can only
|
|
hold a reference to one of them. In this case we recommend defining
|
|
the <literal><context:spring-configured/></literal> bean in the
|
|
shared (parent) application context: this defines the services that
|
|
you are likely to want to inject into domain objects. A consequence is
|
|
that you cannot configure domain objects with references to beans
|
|
defined in the child (servlet-specific) contexts using the
|
|
@Configurable mechanism (probably not something you want to do
|
|
anyway!).</para>
|
|
|
|
<para>When deploying multiple web-apps within the same container,
|
|
ensure that each web-application loads the types in <filename
|
|
class="libraryfile">spring-aspects.jar</filename> using its own
|
|
classloader (for example, by placing <filename
|
|
class="libraryfile">spring-aspects.jar</filename> in <filename
|
|
class="directory">'WEB-INF/lib'</filename>). If <filename
|
|
class="libraryfile">spring-aspects.jar</filename> is only added to the
|
|
container wide classpath (and hence loaded by the shared parent
|
|
classloader), all web applications will share the same aspect instance
|
|
which is probably not what you want.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="aop-ajlib-other">
|
|
<title>Other Spring aspects for AspectJ</title>
|
|
|
|
<para>In addition to the <interfacename>@Configurable</interfacename>
|
|
aspect, <filename class="libraryfile">spring-aspects.jar</filename>
|
|
contains an AspectJ aspect that can be used to drive Spring's
|
|
transaction management for types and methods annotated with the
|
|
<interfacename>@Transactional</interfacename> annotation. This is
|
|
primarily intended for users who want to use the Spring Framework's
|
|
transaction support outside of the Spring container.</para>
|
|
|
|
<para>The aspect that interprets
|
|
<interfacename>@Transactional</interfacename> annotations is the
|
|
<classname>AnnotationTransactionAspect</classname>. When using this
|
|
aspect, you must annotate the <emphasis>implementation</emphasis> class
|
|
(and/or methods within that class), <emphasis>not</emphasis> the
|
|
interface (if any) that the class implements. AspectJ follows Java's
|
|
rule that annotations on interfaces are <emphasis>not
|
|
inherited</emphasis>.</para>
|
|
|
|
<para>A <interfacename>@Transactional</interfacename> annotation on a
|
|
class specifies the default transaction semantics for the execution of
|
|
any <emphasis>public</emphasis> operation in the class.</para>
|
|
|
|
<para>A <interfacename>@Transactional</interfacename> annotation on a
|
|
method within the class overrides the default transaction semantics
|
|
given by the class annotation (if present). Methods with
|
|
<literal>public</literal>, <literal>protected</literal>, and default
|
|
visibility may all be annotated. Annotating <literal>protected</literal>
|
|
and default visibility methods directly is the only way to get
|
|
transaction demarcation for the execution of such methods.</para>
|
|
|
|
<para>For AspectJ programmers that want to use the Spring configuration
|
|
and transaction management support but don't want to (or cannot) use
|
|
annotations, <filename class="libraryfile">spring-aspects.jar</filename>
|
|
also contains <literal>abstract</literal> aspects you can extend to
|
|
provide your own pointcut definitions. See the sources for the
|
|
<classname>AbstractBeanConfigurerAspect</classname> and
|
|
<classname>AbstractTransactionAspect</classname> aspects for more
|
|
information. As an example, the following excerpt shows how you could
|
|
write an aspect to configure all instances of objects defined in the
|
|
domain model using prototype bean definitions that match the
|
|
fully-qualified class names:</para>
|
|
|
|
<programlisting language="java">public aspect DomainObjectConfiguration extends AbstractBeanConfigurerAspect {
|
|
|
|
public DomainObjectConfiguration() {
|
|
setBeanWiringInfoResolver(new ClassNameBeanWiringInfoResolver());
|
|
}
|
|
|
|
<lineannotation>// the creation of a new bean (any object in the domain model)</lineannotation>
|
|
protected pointcut beanCreation(Object beanInstance) :
|
|
initialization(new(..)) &&
|
|
SystemArchitecture.inDomainModel() &&
|
|
this(beanInstance);
|
|
|
|
}</programlisting>
|
|
</section>
|
|
|
|
<section id="aop-aj-configure">
|
|
<title>Configuring AspectJ aspects using Spring IoC</title>
|
|
|
|
<para>When using AspectJ aspects with Spring applications, it is natural
|
|
to both want and expect to be able to configure such aspects using
|
|
Spring. The AspectJ runtime itself is responsible for aspect creation,
|
|
and the means of configuring the AspectJ created aspects via Spring
|
|
depends on the AspectJ instantiation model (the
|
|
'<literal>per-xxx</literal>' clause) used by the aspect.</para>
|
|
|
|
<para>The majority of AspectJ aspects are <emphasis>singleton</emphasis>
|
|
aspects. Configuration of these aspects is very easy: simply create a
|
|
bean definition referencing the aspect type as normal, and include the
|
|
bean attribute <literal>'factory-method="aspectOf"'</literal>. This
|
|
ensures that Spring obtains the aspect instance by asking AspectJ for it
|
|
rather than trying to create an instance itself. For example:</para>
|
|
|
|
<programlisting language="xml"><bean id="profiler" class="com.xyz.profiler.Profiler"
|
|
<emphasis role="bold">factory-method="aspectOf"</emphasis>>
|
|
<property name="profilingStrategy" ref="jamonProfilingStrategy"/>
|
|
</bean></programlisting>
|
|
|
|
<para>Non-singleton aspects are harder to configure: however it is
|
|
possible to do so by creating prototype bean definitions and using the
|
|
<interfacename>@Configurable</interfacename> support from <filename
|
|
class="libraryfile">spring-aspects.jar</filename> to configure the
|
|
aspect instances once they have bean created by the AspectJ
|
|
runtime.</para>
|
|
|
|
<para>If you have some @AspectJ aspects that you want to weave with
|
|
AspectJ (for example, using load-time weaving for domain model types)
|
|
and other @AspectJ aspects that you want to use with Spring AOP, and
|
|
these aspects are all configured using Spring, then you will need to
|
|
tell the Spring AOP @AspectJ autoproxying support which exact subset of
|
|
the @AspectJ aspects defined in the configuration should be used for
|
|
autoproxying. You can do this by using one or more
|
|
<literal><include/></literal> elements inside the
|
|
<literal><aop:aspectj-autoproxy/></literal> declaration. Each
|
|
<literal><include/></literal> element specifies a name pattern,
|
|
and only beans with names matched by at least one of the patterns will
|
|
be used for Spring AOP autoproxy configuration:</para>
|
|
|
|
<programlisting language="xml"><aop:aspectj-autoproxy>
|
|
<aop:include name="thisBean"/>
|
|
<aop:include name="thatBean"/>
|
|
</aop:aspectj-autoproxy></programlisting>
|
|
|
|
<note>
|
|
<para>Do not be misled by the name of the
|
|
<literal><aop:aspectj-autoproxy/></literal> element: using it
|
|
will result in the creation of <emphasis>Spring AOP
|
|
proxies</emphasis>. The @AspectJ style of aspect declaration is just
|
|
being used here, but the AspectJ runtime is <emphasis>not</emphasis>
|
|
involved.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="aop-aj-ltw">
|
|
<title>Load-time weaving with AspectJ in the Spring Framework</title>
|
|
|
|
<para>Load-time weaving (LTW) refers to the process of weaving AspectJ
|
|
aspects into an application's class files as they are being loaded into
|
|
the Java virtual machine (JVM). The focus of this section is on
|
|
configuring and using LTW in the specific context of the Spring
|
|
Framework: this section is not an introduction to LTW though. For full
|
|
details on the specifics of LTW and configuring LTW with just AspectJ
|
|
(with Spring not being involved at all), see the <ulink
|
|
url="http://www.eclipse.org/aspectj/doc/released/devguide/ltw.html">LTW
|
|
section of the AspectJ Development Environment Guide</ulink>.</para>
|
|
|
|
<para>The value-add that the Spring Framework brings to AspectJ LTW is
|
|
in enabling much finer-grained control over the weaving process.
|
|
'Vanilla' AspectJ LTW is effected using a Java (5+) agent, which is
|
|
switched on by specifying a VM argument when starting up a JVM. It is
|
|
thus a JVM-wide setting, which may be fine in some situations, but often
|
|
is a little too coarse. Spring-enabled LTW enables you to switch on LTW
|
|
on a <emphasis>per-<classname>ClassLoader</classname></emphasis> basis,
|
|
which obviously is more fine-grained and which can make more sense in a
|
|
'single-JVM-multiple-application' environment (such as is found in a
|
|
typical application server environment).</para>
|
|
|
|
<para>Further, <link linkend="aop-aj-ltw-environments">in certain
|
|
environments</link>, this support enables load-time weaving
|
|
<emphasis>without making any modifications to the application server's
|
|
launch script</emphasis> that will be needed to add
|
|
-javaagent:path/to/aspectjweaver.jar or (as we describe later in this
|
|
section) -javaagent:path/to/spring-agent.jar. Developers simply modify
|
|
one or more files that form the application context to enable load-time
|
|
weaving instead of relying on administrators who typically are in charge
|
|
of the deployment configuration such as the launch script.</para>
|
|
|
|
<para>Now that the sales pitch is over, let us first walk through a
|
|
quick example of AspectJ LTW using Spring, followed by detailed
|
|
specifics about elements introduced in the following example. For a
|
|
complete example, please see the Petclinic sample application.</para>
|
|
|
|
<section id="aop-aj-ltw-first-example">
|
|
<title>A first example</title>
|
|
|
|
<para>Let us assume that you are an application developer who has been
|
|
tasked with diagnosing the cause of some performance problems in a
|
|
system. Rather than break out a profiling tool, what we are going to
|
|
do is switch on a simple profiling aspect that will enable us to very
|
|
quickly get some performance metrics, so that we can then apply a
|
|
finer-grained profiling tool to that specific area immediately
|
|
afterwards.</para>
|
|
|
|
<para>Here is the profiling aspect. Nothing too fancy, just a
|
|
quick-and-dirty time-based profiler, using the @AspectJ-style of
|
|
aspect declaration.</para>
|
|
|
|
<programlisting language="java">package foo;
|
|
|
|
import org.aspectj.lang.ProceedingJoinPoint;
|
|
import org.aspectj.lang.annotation.Aspect;
|
|
import org.aspectj.lang.annotation.Around;
|
|
import org.aspectj.lang.annotation.Pointcut;
|
|
import org.springframework.util.StopWatch;
|
|
import org.springframework.core.annotation.Order;
|
|
|
|
@Aspect
|
|
public class ProfilingAspect {
|
|
|
|
@Around("methodsToBeProfiled()")
|
|
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
|
|
StopWatch sw = new StopWatch(getClass().getSimpleName());
|
|
try {
|
|
sw.start(pjp.getSignature().getName());
|
|
return pjp.proceed();
|
|
} finally {
|
|
sw.stop();
|
|
System.out.println(sw.prettyPrint());
|
|
}
|
|
}
|
|
|
|
@Pointcut("execution(public * foo..*.*(..))")
|
|
public void methodsToBeProfiled(){}
|
|
}
|
|
</programlisting>
|
|
|
|
<para>We will also need to create an
|
|
'<filename>META-INF/aop.xml</filename>' file, to inform the AspectJ
|
|
weaver that we want to weave our
|
|
<classname>ProfilingAspect</classname> into our classes. This file
|
|
convention, namely the presence of a file (or files) on the Java
|
|
classpath called ' <filename>META-INF/aop.xml</filename>' is standard
|
|
AspectJ.</para>
|
|
|
|
<programlisting language="xml"><!DOCTYPE aspectj PUBLIC
|
|
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
|
|
<aspectj>
|
|
|
|
<weaver>
|
|
|
|
<lineannotation><!-- only weave classes in our application-specific packages --></lineannotation>
|
|
<include within="foo.*"/>
|
|
|
|
</weaver>
|
|
|
|
<aspects>
|
|
|
|
<lineannotation><!-- weave in just this aspect --></lineannotation>
|
|
<aspect name="foo.ProfilingAspect"/>
|
|
|
|
</aspects>
|
|
|
|
</aspectj></programlisting>
|
|
|
|
<para>Now to the Spring-specific portion of the configuration. We need
|
|
to configure a <interfacename>LoadTimeWeaver</interfacename> (all
|
|
explained later, just take it on trust for now). This load-time weaver
|
|
is the essential component responsible for weaving the aspect
|
|
configuration in one or more '<filename>META-INF/aop.xml</filename>'
|
|
files into the classes in your application. The good thing is that it
|
|
does not require a lot of configuration, as can be seen below (there
|
|
are some more options that you can specify, but these are detailed
|
|
later).</para>
|
|
|
|
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?>
|
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xmlns:context="http://www.springframework.org/schema/context"
|
|
xsi:schemaLocation="
|
|
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
|
|
|
|
<lineannotation><!-- a service object; we will be profiling its methods --></lineannotation>
|
|
<bean id="entitlementCalculationService"
|
|
class="foo.StubEntitlementCalculationService"/>
|
|
|
|
<lineannotation><!-- this switches on the load-time weaving --></lineannotation>
|
|
<emphasis role="bold"><context:load-time-weaver/></emphasis>
|
|
|
|
</beans></programlisting>
|
|
|
|
<para>Now that all the required artifacts are in place - the aspect,
|
|
the '<filename>META-INF/aop.xml</filename>' file, and the Spring
|
|
configuration -, let us create a simple driver class with a
|
|
<methodname>main(..)</methodname> method to demonstrate the LTW in
|
|
action.</para>
|
|
|
|
<programlisting language="java">package foo;
|
|
|
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|
|
|
public final class Main {
|
|
|
|
public static void main(String[] args) {
|
|
|
|
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml", Main.class);
|
|
|
|
EntitlementCalculationService entitlementCalculationService
|
|
= (EntitlementCalculationService) ctx.getBean("entitlementCalculationService");
|
|
|
|
<lineannotation>// the profiling aspect is 'woven' around this method execution</lineannotation>
|
|
entitlementCalculationService.calculateEntitlement();
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>There is one last thing to do. The introduction to this section
|
|
did say that one could switch on LTW selectively on a
|
|
per-<classname>ClassLoader</classname> basis with Spring, and this is
|
|
true. However, just for this example, we are going to use a Java agent
|
|
(supplied with Spring) to switch on the LTW. This is the command line
|
|
we will use to run the above <classname>Main</classname> class:</para>
|
|
|
|
<programlisting>java -javaagent:C:/projects/foo/lib/global/spring-agent.jar foo.Main</programlisting>
|
|
|
|
<para>The '<literal>-javaagent</literal>' is a Java 5+ flag for
|
|
specifying and enabling <ulink
|
|
url="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/instrument/package-summary.html">agents
|
|
to instrument programs running on the JVM</ulink>. The Spring
|
|
Framework ships with such an agent, the
|
|
<classname>InstrumentationSavingAgent</classname>, which is packaged
|
|
in the <filename class="libraryfile">spring-agent.jar</filename> that
|
|
was supplied as the value of the <literal>-javaagent</literal>
|
|
argument in the above example.</para>
|
|
|
|
<para>The output from the execution of the <classname>Main</classname>
|
|
program will look something like that below. (I have introduced a
|
|
<methodname>Thread.sleep(..)</methodname> statement into the
|
|
<methodname>calculateEntitlement()</methodname> implementation so that
|
|
the profiler actually captures something other than 0 milliseconds -
|
|
the <literal>01234</literal> milliseconds is <emphasis>not</emphasis>
|
|
an overhead introduced by the AOP :) )</para>
|
|
|
|
<programlisting>Calculating entitlement
|
|
|
|
StopWatch 'ProfilingAspect': running time (millis) = 1234
|
|
------ ----- ----------------------------
|
|
ms % Task name
|
|
------ ----- ----------------------------
|
|
01234 100% calculateEntitlement</programlisting>
|
|
|
|
<para>Since this LTW is effected using full-blown AspectJ, we are not
|
|
just limited to advising Spring beans; the following slight variation
|
|
on the <classname>Main</classname> program will yield the same
|
|
result.</para>
|
|
|
|
<programlisting language="java">package foo;
|
|
|
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
|
|
|
public final class Main {
|
|
|
|
public static void main(String[] args) {
|
|
|
|
new ClassPathXmlApplicationContext("beans.xml", Main.class);
|
|
|
|
EntitlementCalculationService entitlementCalculationService =
|
|
new StubEntitlementCalculationService();
|
|
|
|
<lineannotation>// the profiling aspect will be 'woven' around this method execution</lineannotation>
|
|
entitlementCalculationService.calculateEntitlement();
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Notice how in the above program we are simply bootstrapping the
|
|
Spring container, and then creating a new instance of the
|
|
<classname>StubEntitlementCalculationService</classname> totally
|
|
outside the context of Spring... the profiling advice still gets woven
|
|
in.</para>
|
|
|
|
<para>The example admittedly is simplistic... however the basics of
|
|
the LTW support in Spring have all been introduced in the above
|
|
example, and the rest of this section will explain the 'why' behind
|
|
each bit of configuration and usage in detail.</para>
|
|
|
|
<note>
|
|
<para>The <classname>ProfilingAspect</classname> used in this
|
|
example may be basic, but it is quite useful. It is a nice example
|
|
of a development-time aspect that developers can use during
|
|
development (of course), and then quite easily exclude from builds
|
|
of the application being deployed into UAT or production.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="aop-aj-ltw-the-aspects">
|
|
<title>Aspects</title>
|
|
|
|
<para>The aspects that you use in LTW have to be AspectJ aspects. They
|
|
can be written in either the AspectJ language itself or you can write
|
|
your aspects in the @AspectJ-style. The latter option is of course
|
|
only an option if you are using Java 5+, but it does mean that your
|
|
aspects are then both valid AspectJ <emphasis>and</emphasis> Spring
|
|
AOP aspects. Furthermore, the compiled aspect classes need to be
|
|
available on the classpath.</para>
|
|
</section>
|
|
|
|
<section id="aop-aj-ltw-aop_dot_xml">
|
|
<title>'<filename>META-INF/aop.xml</filename>'</title>
|
|
|
|
<para>The AspectJ LTW infrastructure is configured using one or more
|
|
'<filename>META-INF/aop.xml</filename>' files, that are on the Java
|
|
classpath (either directly, or more typically in jar files).</para>
|
|
|
|
<para>The structure and contents of this file is detailed in the main
|
|
AspectJ reference documentation, and the interested reader is <ulink
|
|
url="http://www.eclipse.org/aspectj/doc/released/devguide/ltw-configuration.html">referred
|
|
to that resource</ulink>. (I appreciate that this section is brief,
|
|
but the '<filename>aop.xml</filename>' file is 100% AspectJ - there is
|
|
no Spring-specific information or semantics that apply to it, and so
|
|
there is no extra value that I can contribute either as a result), so
|
|
rather than rehash the quite satisfactory section that the AspectJ
|
|
developers wrote, I am just directing you there.)</para>
|
|
</section>
|
|
|
|
<section id="aop-aj-ltw-libraries">
|
|
<title>Required libraries (JARS)</title>
|
|
|
|
<para>At a minimum you will need the following libraries to use the
|
|
Spring Framework's support for AspectJ LTW:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para><filename class="libraryfile">spring.jar</filename> (version
|
|
2.5 or later)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="libraryfile">aspectjrt.jar</filename>
|
|
(version 1.5 or later)</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><filename class="libraryfile">aspectjweaver.jar</filename>
|
|
(version 1.5 or later)</para>
|
|
</listitem>
|
|
</orderedlist>
|
|
|
|
<para>If you are using the <link
|
|
linkend="aop-aj-ltw-environment-generic">Spring-provided agent to
|
|
enable instrumentation</link>, you will also need:</para>
|
|
|
|
<orderedlist>
|
|
<listitem>
|
|
<para><filename
|
|
class="libraryfile">spring-agent.jar</filename></para>
|
|
</listitem>
|
|
</orderedlist>
|
|
</section>
|
|
|
|
<section id="aop-aj-ltw-spring">
|
|
<title>Spring configuration</title>
|
|
|
|
<para>The key component in Spring's LTW support is the
|
|
<interfacename>LoadTimeWeaver</interfacename> interface (in the
|
|
<literal>org.springframework.instrument.classloading</literal>
|
|
package), and the numerous implementations of it that ship with the
|
|
Spring distribution. A <interfacename>LoadTimeWeaver</interfacename>
|
|
is responsible for adding one or more
|
|
<classname>java.lang.instrument.ClassFileTransformers</classname> to a
|
|
<classname>ClassLoader</classname> at runtime, which opens the door to
|
|
all manner of interesting applications, one of which happens to be the
|
|
LTW of aspects.</para>
|
|
|
|
<tip>
|
|
<para>If you are unfamiliar with the idea of runtime class file
|
|
transformation, you are encouraged to read the Javadoc API
|
|
documentation for the <literal>java.lang.instrument</literal>
|
|
package before continuing. This is not a huge chore because there is
|
|
- rather annoyingly - precious little documentation there... the key
|
|
interfaces and classes will at least be laid out in front of you for
|
|
reference as you read through this section.</para>
|
|
</tip>
|
|
|
|
<para>Configuring a <interfacename>LoadTimeWeaver</interfacename>
|
|
using XML for a particular
|
|
<interfacename>ApplicationContext</interfacename> can be as easy as
|
|
adding one line. (Please note that you almost certainly will need to
|
|
be using an <interfacename>ApplicationContext</interfacename> as your
|
|
Spring container - typically a
|
|
<interfacename>BeanFactory</interfacename> will not be enough because
|
|
the LTW support makes use of
|
|
<interfacename>BeanFactoryPostProcessors</interfacename>.)</para>
|
|
|
|
<para>To enable the Spring Framework's LTW support, you need to
|
|
configure a <interfacename>LoadTimeWeaver</interfacename>, which
|
|
typically is done using the
|
|
<literal><context:load-time-weaver/></literal> element. Find
|
|
below a valid <literal><context:load-time-weaver/></literal>
|
|
definition that uses default settings.</para>
|
|
|
|
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?>
|
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xmlns:context="http://www.springframework.org/schema/context"
|
|
xsi:schemaLocation="
|
|
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
|
|
|
|
<context:load-time-weaver/>
|
|
|
|
</beans></programlisting>
|
|
|
|
<para>The above <literal><context:load-time-weaver/></literal>
|
|
bean definition will define and register a number of LTW-specific
|
|
infrastructure beans for you automatically, such as a
|
|
<interfacename>LoadTimeWeaver</interfacename> and an
|
|
<classname>AspectJWeavingEnabler</classname>. Notice how the
|
|
<literal><context:load-time-weaver/></literal> is defined in the
|
|
'<literal>context</literal>' namespace; note also that the referenced
|
|
XML Schema file is only available in versions of Spring 2.5 and
|
|
later.</para>
|
|
|
|
<para>What the above configuration does is define and register a
|
|
default <interfacename>LoadTimeWeaver</interfacename> bean for you.
|
|
The default <interfacename>LoadTimeWeaver</interfacename> is the
|
|
<classname>DefaultContextLoadTimeWeaver</classname> class, which
|
|
attempts to decorate an automatically detected
|
|
<interfacename>LoadTimeWeaver</interfacename>: the exact type of
|
|
<interfacename>LoadTimeWeaver</interfacename> that will be
|
|
'automatically detected' is dependent upon your runtime environment
|
|
(summarised in the following table).</para>
|
|
|
|
<table id="aop-aj-ltw-spring-env-impls" pgwide="1">
|
|
<title><classname>DefaultContextLoadTimeWeaver</classname>
|
|
<interfacename>LoadTimeWeavers</interfacename></title>
|
|
|
|
<tgroup cols="2">
|
|
<colspec align="left" />
|
|
|
|
<thead>
|
|
<row>
|
|
<entry>Runtime Environment</entry>
|
|
<entry><interfacename>LoadTimeWeaver</interfacename> implementation</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><para>Running in <ulink
|
|
url="http://www.bea.com/framework.jsp?CNT=index.htm&FP=/content/products/weblogic/server">BEA's
|
|
Weblogic 10</ulink></para></entry>
|
|
<entry><para><classname>WebLogicLoadTimeWeaver</classname></para></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><para>Running in <ulink
|
|
url="http://www.oracle.com/technology/products/oc4j/index.html">Oracle's
|
|
OC4J</ulink></para></entry>
|
|
<entry><para><classname>OC4JLoadTimeWeaver</classname></para></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><para>Running in <ulink url="http://glassfish.dev.java.net/">GlassFish</ulink></para></entry>
|
|
<entry><para><classname>GlassFishLoadTimeWeaver</classname></para></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><para>JVM started with Spring
|
|
<classname>InstrumentationSavingAgent</classname></para>
|
|
<para><emphasis><literal>(java
|
|
-javaagent:path/to/spring-agent.jar)</literal></emphasis></para></entry>
|
|
<entry><para><classname>InstrumentationLoadTimeWeaver</classname></para></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><para>Fallback, expecting the underlying ClassLoader to follow common conventions
|
|
(e.g. applicable to <classname>TomcatInstrumentableClassLoader</classname> and to Resin)</para></entry>
|
|
<entry><para><classname>ReflectiveLoadTimeWeaver</classname></para></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
|
|
<para>Note that these are just the
|
|
<interfacename>LoadTimeWeavers</interfacename> that are autodetected
|
|
when using the <classname>DefaultContextLoadTimeWeaver</classname>: it
|
|
is of course possible to specify exactly which
|
|
<interfacename>LoadTimeWeaver</interfacename> implementation that you
|
|
wish to use by specifying the fully-qualified classname as the value
|
|
of the '<literal>weaver-class</literal>' attribute of the
|
|
<literal><context:load-time-weaver/></literal> element. Find
|
|
below an example of doing just that:</para>
|
|
|
|
<programlisting language="xml"><?xml version="1.0" encoding="UTF-8"?>
|
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
xmlns:context="http://www.springframework.org/schema/context"
|
|
xsi:schemaLocation="
|
|
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
|
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
|
|
|
|
<context:load-time-weaver
|
|
<emphasis role="bold">weaver-class="org.springframework.instrument.classloading.ReflectiveLoadTimeWeaver"</emphasis>/>
|
|
|
|
</beans></programlisting>
|
|
|
|
<para>The <interfacename>LoadTimeWeaver</interfacename> that is
|
|
defined and registered by the
|
|
<literal><context:load-time-weaver/></literal> element can be
|
|
later retrieved from the Spring container using the well-known name
|
|
'<literal>loadTimeWeaver</literal>'. Remember that the
|
|
<interfacename>LoadTimeWeaver</interfacename> exists just as a
|
|
mechanism for Spring's LTW infrastructure to add one or more
|
|
<interfacename>ClassFileTransformers</interfacename>. The actual
|
|
<classname>ClassFileTransformer</classname> that does the LTW is the
|
|
<classname>ClassPreProcessorAgentAdapter</classname> (from the
|
|
<literal>org.aspectj.weaver.loadtime</literal> package) class. See the
|
|
class-level Javadoc for the
|
|
<classname>ClassPreProcessorAgentAdapter</classname> class for further
|
|
details, because the specifics of how the weaving is actually effected
|
|
is beyond the scope of this section.</para>
|
|
|
|
<para>There is one final attribute of the
|
|
<literal><context:load-time-weaver/></literal> left to discuss:
|
|
the '<literal>aspectj-weaving</literal>' attribute. This is a simple
|
|
attribute that controls whether LTW is enabled or not, it is as simple
|
|
as that. It accepts one of three possible values, summarised below,
|
|
with the default value if the attribute is not present being '
|
|
<literal>autodetect</literal>'</para>
|
|
|
|
<table id="aop-aj-ltw-ltw-tag-attrs" pgwide="1">
|
|
<title>'<literal>aspectj-weaving</literal>' attribute values</title>
|
|
|
|
<tgroup cols="2">
|
|
<colspec align="left" />
|
|
|
|
<thead>
|
|
<row>
|
|
<entry>Attribute Value</entry>
|
|
<entry>Explanation</entry>
|
|
</row>
|
|
</thead>
|
|
|
|
<tbody>
|
|
<row>
|
|
<entry><para><literal>on</literal></para></entry>
|
|
<entry><para>AspectJ weaving is on, and aspects will be woven
|
|
at load-time as appropriate.</para></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><para><literal>off</literal></para></entry>
|
|
<entry><para>LTW is off... no aspect will be woven at
|
|
load-time.</para></entry>
|
|
</row>
|
|
|
|
<row>
|
|
<entry><para><literal>autodetect</literal></para></entry>
|
|
<entry><para>If the Spring LTW infrastructure can find at
|
|
least one '<filename>META-INF/aop.xml</filename>' file, then
|
|
AspectJ weaving is on, else it is off. This is the default
|
|
value.</para></entry>
|
|
</row>
|
|
</tbody>
|
|
</tgroup>
|
|
</table>
|
|
</section>
|
|
|
|
<section id="aop-aj-ltw-environments">
|
|
<title>Environment-specific configuration</title>
|
|
|
|
<para>This last section contains any additional settings and
|
|
configuration that you will need when using Spring's LTW support in
|
|
environments such as application servers and web containers.</para>
|
|
|
|
<section id="aop-aj-ltw-environment-generic">
|
|
<title>Generic Java applications</title>
|
|
|
|
<para>You may enable Spring's support for LTW in any Java application
|
|
(standalone as well as application server based) through the use of
|
|
the Spring-provided instrumentation agent. To do so, start
|
|
the VM by by specifying the
|
|
<literal>-javaagent:path/to/spring-agent.jar</literal> option.
|
|
Note that this requires modification of the VM launch script
|
|
which may prevent you from using this in application server
|
|
environments (depending on your operation policies).</para>
|
|
</section>
|
|
|
|
<section id="aop-aj-ltw-environment-tomcat">
|
|
<title>Tomcat</title>
|
|
|
|
<para>For web applications deployed onto Apache Tomcat 5.0 and above,
|
|
Spring provides a <classname>TomcatInstrumentableClassLoader</classname>
|
|
to be registered as the web app class loader. The required Tomcat setup
|
|
looks as follows, to be included either in Tomcat's central
|
|
<literal>server.xml</literal> file or in an application-specific
|
|
<literal>META-INF/context.xml</literal> file within the WAR root.
|
|
Spring's <literal>spring-tomcat-weaver.jar</literal> needs to be
|
|
included in Tomcat's common lib directory in order to make this
|
|
setup work.</para>
|
|
|
|
<programlisting language="xml"><Context path="/myWebApp" docBase="/my/webApp/location">
|
|
<Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
|
|
useSystemClassLoaderAsParent="false"/>
|
|
</Context>
|
|
</programlisting>
|
|
|
|
<para><emphasis>Note: We generally recommend Tomcat 5.5.20 or above
|
|
when enabling load-time weaving.</emphasis> Prior versions have known
|
|
issues with custom <classname>ClassLoader</classname> setup.</para>
|
|
|
|
<para>Alternatively, consider the use of the Spring-provided generic
|
|
VM agent, to be specified in Tomcat's launch script (see above).
|
|
This will make instrumentation available to all deployed web
|
|
applications, no matter which ClassLoader they happen to run on.</para>
|
|
|
|
<para>For a more detailed discussion of Tomcat-based weaving setup,
|
|
check out the <xref linkend="orm-jpa-setup-lcemfb-tomcat"/> section
|
|
which discusses specifics of various Tomcat versions. While the primary
|
|
focus of that section is on JPA persistence provider setup, the Tomcat
|
|
setup characteristics apply to general load-time weaving as well.</para>
|
|
</section>
|
|
|
|
<section id="aop-aj-ltw-environments-weblogic-oc4j-resin-glassfish">
|
|
<title>WebLogic, OC4J, Resin, GlassFish</title>
|
|
|
|
<para>Recent versions of BEA WebLogic (version 10 and above), Oracle
|
|
Containers for Java EE (OC4J 10.1.3.1 and above) and Resin (3.1 and above)
|
|
provide a ClassLoader that is capable of local instrumentation.
|
|
Spring's native LTW leverages such ClassLoaders to enable AspectJ weaving.
|
|
You can enable LTW by simply activating <literal>context:load-time-weaver</literal>
|
|
as described earlier. Specifically, you do <emphasis>not</emphasis>
|
|
need to modify the launch script to add
|
|
<literal>-javaagent:path/to/spring-agent.jar</literal>.</para>
|
|
|
|
<para>GlassFish provides an instrumentation-capable ClassLoader as well,
|
|
but only in its EAR environment. For GlassFish web applications,
|
|
follow the Tomcat setup instructions as outlined above.</para>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="aop-resources">
|
|
<title>Further Resources</title>
|
|
|
|
<para>More information on AspectJ can be found on the <ulink
|
|
url="http://www.eclipse.org/aspectj">AspectJ website</ulink>.</para>
|
|
|
|
<para>The book <emphasis>Eclipse AspectJ</emphasis> by Adrian Colyer et.
|
|
al. (Addison-Wesley, 2005) provides a comprehensive introduction and
|
|
reference for the AspectJ language.</para>
|
|
|
|
<para>The book <emphasis>AspectJ in Action</emphasis> by Ramnivas Laddad
|
|
(Manning, 2003) comes highly recommended; the focus of the book is on
|
|
AspectJ, but a lot of general AOP themes are explored (in some depth).</para>
|
|
</section>
|
|
|
|
</chapter>
|