Recipe14.2.Defining an Aspect per Instance


Recipe 14.2. Defining an Aspect per Instance

Problem

You want to declare that an aspect is to be instantiated on a per-object-instance basis.

Solution

Use the perthis(Pointcut) or pertarget(Pointcut) aspect instantiation policy declarations.

Discussion

AspectJ provides the perthis(Pointcut) and pertarget(Pointcut) aspect instantiation policies to declare an aspect should be instantiated for every new object instance according to the classes selected with the Pointcut definition.

The difference between the perthis(Pointcut) and the pertarget(Pointcut) declarations has to do with what object is examined when an advised join point is reached. The perthis(Pointcut) declaration specifies that a new aspect will be instantiated for every new object referenced by this at the advice triggering join point. The pertarget(Pointcut) instantiation policy specifies that a new aspect will be instantiated for every new object that is the target of an advice triggering join point. Despite these subtle differences, both declarations explicitly associate a single aspect instance to a single object instance.

Example 14-2 shows how a perthis(Pointcut) declaration can be assigned to a particular aspect, and Figure 14-2 shows how the aspect instantiation policy is realized within the flow of an application.

Example 14-2. Using the perthis(Pointcut) declaration to instantiate an aspect for every executing object
public aspect PerThis perthis(callPointCut( )) {    /*    Specifies calling advice whenever a method    matching the following rules is executed:        Class Name: MyClass    Method Name: foo    Method Return Type: void    Method Parameters: an int followed by a String    */    pointcut callPointCut( ) : call(       void MyClass.foo(int, String));    // Advice declaration    before( ) : callPointCut( ) && !within(PerThis +)    {       System.out.println(          "------------------- Aspect Advice Logic --------------------");       System.out.println(          "In the advice attached to the call point cut");       System.out.println("Target: " + thisJoinPoint.getTarget( ));       System.out.println("This: " + thisJoinPoint.getThis( ));       System.out.println(          "Aspect Instance: "             + PerThis.aspectOf(thisJoinPoint.getThis( )));       System.out.println(          "------------------------------------------------------------");    } }

Figure 14-2. Creating one aspect instance per object advised


The Pointcut parameter on the perthis(Pointcut) and pertarget(Pointcut) aspect instantiation policy declarations raises some interesting questions when you consider that multiple classes can be advised by a single aspect. Example 14-3 shows how an aspect can be declared to advise multiple classes where the perthis(Pointcut) aspect instantiation policy is only relevant on objects of the MyClass class as specified by the executeMyClassFoo( ) pointcut.

Example 14-3. Attempting to advise multiple classes but specifying an aspect instantiation policy that is only interested in one class
public aspect AdviseMultipleClasses perthis(executeMyClassFoo( )) {         public pointcut executeMyClassFoo( ) : execution(void MyClass.foo( ));                  public pointcut executeAnotherClassFoo( ) : execution(         void AnotherClass.foo( ));                  before( ) : executeMyClassFoo( )         {                 System.out.println("Advising foo");                 System.out.println("Aspect is: " + this);         }                  before( ) : executeAnotherClassFoo( )         {                 System.out.println("Advising foo");                 System.out.println("Aspect is: " + this);         } }

Declaring that the AdviseMultipleClasses aspect is only to be instantiated for every new object as specified by the executeMyClassFoo( ) pointcut implicitly excludes other classes of object. Even though the executeAnotherClassFoo( ) pointcut is declared and has corresponding advice, it will not result in any aspects being applied to classes other than those that it shares with executeMyClassFoo( ).

In Example 14-3, no common classes are shared between the two pointcuts, so the executeMyClassFoo( ) pointcut and associated advice is ignored because this pointcut is taking part in the definition of the perthis(Pointcut) instantiation policy, as shown in Figure 14-3.

Figure 14-3. Implicitly excluding AnotherClass objects from the AdviseMultipleAspects aspect according to the aspect instantiation policy


An aspect cannot have two instantiation policies for two different types of object. To ensure that an aspect's instantiation policy is relevant for all objects of the classes that it advises, a useful idiom is to declare a pointcut that combines all other pointcut declarations in the aspect purely for the use of the aspect's instantiation policy, as shown in Example 14-4.

Example 14-4. Capturing all classes that are advised by an aspect for inclusion into the aspect instantiation policy definition
public aspect AdviseMultipleClasses perthis(applyLifecyclePolicy( )) {         public pointcut executeMyClassFoo( ) : execution(void MyClass.foo( ));                  public pointcut executeAnotherClassFoo( ) : execution(                                                     void AnotherClass.foo( ));                  public pointcut applyLifecyclePolicy( ) : executeMyClassFoo( ) ||                                                   executeAnotherClassFoo( );                  before( ) : executeMyClassFoo( )         {                 System.out.println("Advising foo");                 System.out.println("Aspect is: " + this);         }                  before( ) : executeAnotherClassFoo( )         {                 System.out.println("Advising foo");                 System.out.println("Aspect is: " + this);         } }

See Also

The execution(Signature) pointcut is covered in Recipe 4.4; the within(TypePattern) pointcut is described in Recipe 7.1; the OR(||) operator is described in Recipe 12.3; the NOT(!) operator is described in Recipe 12.4; the Singleton aspect instantiation policy is described in Recipe 14.1.



AspectJ Cookbook
Aspectj Cookbook
ISBN: 0596006543
EAN: 2147483647
Year: 2006
Pages: 203
Authors: Russ Miles

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net