You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3664 lines
168 KiB
3664 lines
168 KiB
<?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>
|
|
|