views:

46

answers:

2

it's convenient for AOP (e.g. AspectJ, SpringAOP) to deal with(advise on) crosscut concerns at pointcuts around methods below,

"Sandwich" code

methodA {
    crosscut code
    user code A
    crosscut code
}

methodB {
    crosscut code
    user code B
    crosscut code
}

Is AOP apt to crosscut concerns overlapped to user code below? How?

"Spaghetti" code

methodX {
    user code x1
    crosscut code

    user code x2
    crosscut code
}

methodY {

    user code y1
    crosscut code

    user code y2
    crosscut code
}

Thanks!

+2  A: 

While some AOP implementations might allow you to do this, this could be indicative of need to refactor those methods into more composed methods as they might be doing too much if one has the need to crosscut concerns into the middle of the methods. Doing so would give you this:

methodX 
{
    usercodemethod1();
    usercodemethod2();
}

usercodemethod1
{
    user code x1
    crosscut code
}

usercodemethod2
{
    user code x2
    crosscut code
}
saret
We do refactoring in terms of best practice. Is the refactoring carting to AOP a good practice in general? If not so, we'd admit AOP is apt to fairly constraint problem domains, e.g. green light to transaction demarcation, but red to logging.
sof
I wouldn't say one should refactor just to cater to AOP, however as mentioned by @seanizer, spring won't help with this, so this might be you best bet if you're going that route - any proxy (runtime) based AOP will normally not support weaving code into the middle of a method
saret
@saret: this won't work with proxy based aop. when methodX calls usercodemethod1 (assuming they are in the same class), it doesn't call the proxy but the actual class (you're already inside the proxy), so the advices don't get a chance to execute. So the only way to achieve this is to make the entire workflow accessible from the outside (client calls usercodemethod1, then usercodemethod2 etc.), which will massively violate the DRY principle.
seanizer
@seanizer if those methods are overridable (such as protected virtual method) then the proxy could inject code into them
saret
that would require cglib, that's not possible with interface based jdk proxies (which are the standard means for spring aop).
seanizer
+1 for the refactoring suggestion. I was just about to say that...
Eran Harel
+1  A: 

Spring AOP won't help, as it only understands the execution() pointcut.

AspectJ includes a lot more pointcuts, including the withincode() construct, which sounds like what you want:

withincode(* YourClass.methodX(. .))

this lets you advise all join points inside a given method exection

Read AspectJ in Action for more info, it's a very good book about both AspectJ and Spring AOP.


EDIT:

here is some sample code:

package com.dummy.aspectj;

import java.util.Arrays;
import java.util.Collections;

public class DummyClass{

    public static void main(final String[] args){
        System.out.println(Arrays.asList("One", Collections.singleton("Two")));
        System.out.println("Enough?");
    }

}

package com.dummy.aspectj;

import java.util.Arrays;

public aspect DummyAspect{

    pointcut callWithinMain() : 
        withincode(* com.dummy.aspectj.DummyClass.main(..)) // anything inside DummyClass.main
        && call(* *.*(..));                                 // but only method calls

    before() : callWithinMain() {
        System.out.println("\n***************************************************");
        System.out.println("** Calling:\n**\t"
            + thisJoinPointStaticPart.getSignature()
            + "\n** with arguments:\n**\t "
            + Arrays.deepToString(thisJoinPoint.getArgs()) );
        System.out.println("***************************************************\n");
    }

}

running the DummyClass from Eclipse / AJDT generates this output:

***************************************************
** Calling:
**  Set java.util.Collections.singleton(Object)
** with arguments:
**   [Two]
***************************************************


***************************************************
** Calling:
**  List java.util.Arrays.asList(Object[])
** with arguments:
**   [[One, [Two]]]
***************************************************


***************************************************
** Calling:
**  void java.io.PrintStream.println(Object)
** with arguments:
**   [[One, [Two]]]
***************************************************

[One, [Two]]

***************************************************
** Calling:
**  void java.io.PrintStream.println(String)
** with arguments:
**   [Enough?]
***************************************************

Enough?
seanizer
Do you have a handy example so to place it here? Thanks for enlightenment!
sof
see my updated post for some sample code
seanizer
Oh! enough for digestion.
sof
read the book, as I said. it's great!
seanizer