Secrets of the Spring AOP Proxy

By Jim White (Director of Training and instructor)

Spring Aspect Oriented Programming (AOP) is a powerful mechanism to weave cross cutting concerns like security, transactions, exception handling, logging, etc. into business code ("core concerns") without explicitly adding calls to the cross cutting concern.  This allows the cross cutting concern to be updated, removed, swapped out, and generally maintained in a much simpler fashion.

AOP Under the Covers – the Proxy

Having said that, because of the way AOP is implemented, there can seem to be a certain amount of mystery and magic at work.  Your code never invokes the advice methods of an aspect class.  Spring does it for you based on your XML configuration or annotations on the aspect class.  How does the magic happen?  Under the covers, Spring implements a proxy to intercept calls to a target object. 

As an example, say you have a service bean that invokes a call to the saveCustomer( ) method on a DAO.

image

Now say you want to have some logging (a cross cutting concern) occur when a call to any save method occurs on a DAO.  Spring detects your need to call on a logging aspect through your AOP configuration or annotations.  When it does, it builds a proxy (called CustomerDaoProxy for example sake here) around the "target" object – in this case the DAO.

image

Now, on a call to a save method in the DAO, the proxy intercepts the call and routes it appropriately to the appropriate advice method in the aspect class.

image

Issues Given Proxy-based AOP

This proxy-based mechanism allows powerful cross cutting concern code to be isolated from business code.  However, there are all kinds of "gotcha’s" that can occur with this type of under-the-covers implementation of which you should be aware.  First of all, aspects cannot advise other aspects.  Per the Spring documentation:

Advising aspects with other aspects?

In Spring AOP, it is not possible to have aspects themselves be the target of advice from other aspects. The @Aspect annotation on a class marks it as an aspect, and hence excludes it from auto-proxying.  (See:  static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-at-aspectj).

This can have some big implications in, sometimes even limitations on, how you implement a cross cutting concern.  Say, for example, your form of logging required adding log statements to a database.  Further, say this database entry required to be performed as part of a transaction (probably a reasonable assumption).  If transactions were implemented through aspects, then you would have the log aspect a target of advice from a transaction aspect.  That’s a big "NGH" – not gonna happen.

image

Another such "gotcha" is that local or internal calls to methods within a target object do not cause the advice method to be invoked even with both methods are captured by the AOP pointcut.  In other words, a call from a method in a target to another method in the target does not get intercepted by the proxy.  This results in the advice method never being triggered.  For example, assume you had some sort of business bean that made a call to itself as shown in the simple example below.

   1: @Component("mySubordinate")
   2: public class CoreBusinessSubordinate {
   3:     
   4:     public void doSomethingBig() {
   5:         System.out.println("I did something small");
   6:     }
   7:     
   8:     public void doSomethingSmall(int x){
   9:         System.out.println("I also do something small but with an int");    
  10:     }
  11: }

Also assume you had an aspect constructed and configured with a pointcut capturing both CoreBusinessSubordinate methods as the CrossCuttingConcern class shown here.

   1: @Component
   2: @Aspect
   3: public class CrossCuttingConcern {
   4:     
   5:     @Before("execution(* com.intertech.CoreBusinessSubordinate.*(..))")
   6:     public void doCrossCutStuff(){
   7:         System.out.println("Doing the cross cutting concern now");
   8:     }
   9: }

If another bean was to explicitly call both the target doSomethingBig( ) and doSomethingSmall( ) methods directly, the proxy/interceptor of the aspect would cause the advice to fire twice – as expected.

   1: @Service
   2: public class CoreBusinessKickOff {
   3:     
   4:     @Autowired
   5:     CoreBusinessSubordinate subordinate;
   6:  
   7:     // getter/setters
   8:     
   9:     public void kickOff() {
  10:         System.out.println("I do something big");
  11:         subordinate.doSomethingBig();
  12:         subordinate.doSomethingSmall(4);
  13:     }
  14: }

Results of calling kickOff above given code above.

I do something big

Doing the cross cutting concern now

I did something small

Doing the cross cutting concern now

I also do something small but with an int

However, if instead of calling the doSomethingSmall( ) method from another bean, it was called from inside the target as shown in this next example, the advice fires only one time!

   1: @Component("mySubordinate")
   2: public class CoreBusinessSubordinate {
   3:     
   4:     public void doSomethingBig() {
   5:         System.out.println("I did something small");
   6:         doSomethingSmall(4);
   7:     }
   8:     
   9:     public void doSomethingSmall(int x){
  10:         System.out.println("I also do something small but with an int");    
  11:     }
  12: }
  13:  
  14: --------------------------------------------
  15:  
  16: public void kickOff() {
  17:     System.out.println("I do something big");
  18:     subordinate.doSomethingBig();
  19:     //subordinate.doSomethingSmall(4);
  20: }

New results of calling kickOff above.

I do something big

Doing the cross cutting concern now

I did something small

I also do something small but with an int

The internal call from the target method to another target method escapes the aspect interceptor.

Work Around

You can sometimes find a work around for AOP proxy issues.  For example, you can work around this last issue by exposing the proxy to the target.  When configuring autoproxy development in your configuration, add an expose-proxy attribute and set its value to true (by default it is false).

   1: <aop:aspectj-autoproxy expose-proxy="true"/>

Now in your target code, you can reroute self-invocating methods back through the target proxy.  Use AopContext.currentProxy( ) to get the proxy object and then invoke the internal target method through the proxy as shown below.

   1: public void doSomethingBig() {
   2:     System.out.println("I did something small");
   3:     //doSomethingSmall(4);
   4:     ((CoreBusinessSubordinate) AopContext.currentProxy()).doSomethingSmall(4);
   5: }

Of course, take heed that this tightly couples your core business concern to AOP – something you are trying to avoid with AOP to begin with.  So it may be better to refactor the code such that internal calls are not required when you need advice to fire on all methods.

Wrap Up

I owe a "thanks for the great question" credit to one of my students (Johannes) from my latest Spring  class.  Through some of his experimentation and questions in class, he provided the inspiration for this blog post.  Or as I like to say in class, he won the "stump-the-chump" award this week with yours truly serving as the chump.  If you would like to learn more about Spring please consider taking Intertech’s Complete Spring Framework 3 class (see here).  Please contact Dan McCabe for further details.

  • shivani

    Thanks.. This blog was of great help…

  • shivani

    Thanks.. the blog was of great help

  • shivani

    Thanks… The blog was of great help

  • http://voice2phone.com/ – auto dialer system

    I suggest this site to my friends so it could be useful & informative for them also. Great effort.

  • Alis

    Nice blog and nice post, The topic here i found is really effective.

  • Alis

    Nice blog and nice post, The topic here i found is really effective.
    <a href="http://www.fabprankcalls.com">Prank Calls</a>

  • Alis

    Nice blog and nice post, The topic here i found is really effective.
    http://www.fabprankcalls.com

  • michael kors outlet

    Some come cheaply tagged while others are extremely expensive. But what is this craze over trendy designer handbags? Why are women of all ages going gaga over these items? They have enamored women of all walks of life, and many of these women do not even question the cost. Certainly, there could not be a difference so significant that it would justify spending so much on such an item!Designer handbags are, in truth, no different from any other kind of handbag. Expensive or not, hangbgssale789 they are [url=http://www.cheaplvbagsus4u.com/]Replica Louis Vuitton Handbags[/url] all made simply to hold a woman's possessions, such as her driving license, lipstick, makeup, [url=http://www.cheaplvbagsus4u.com/louis-vuitton-handbags.html]Louis Vuitton Handbags Replica[/url] money, etc.The fact of the matter is that a designer label has everything to do with [url=http://www.cheaplvbagsus4u.com/]Replica Louis Vuitton Bags[/url] the craze over designer handbags.

  • Tina

    Some posts really matters because they are valueable, I have found your post very valueable.
    http://www.070numbers.com

  • Iffi

    Glad to read your post :). It is very informative!
    http://www.iftekharahmed.com
    http://www.squidoo.com/iftekhar-ahmed

  • voip service providers

    I read and walked for miles at night along the beach, writing bad blank verse and searching endlessly for someone wonderful who would step out of the darkness and change my life. It never crossed my mind that that person could be me.

    <a href="http://www.xinix.co.uk/business-voip-providers-voip-phone-systems-services/">voip service providers</a>

  • Vivek

    Really good one, it did help me a lot to understand how does the proxy works internally with in Spring..

    A question here though, what is the workaround for the having two aspects as in your example above, logging and transaction.. Please explain with an example..

    Vivek

    • http://meta64.com/wclayf Clay Ferguson

      Vivek, I’m waiting to see that one too! If that can be done cleanly I’ll keep using Spring AOP, but if not, I may just ditch it.

  • JWhite

    Vivek – good question. The answer that is often provided is that you have to have your aspect class make a direct call to the other class (say have the transaction aspect call the logging class directly), or create a combines aspect – call it the logging/transaction aspect that does both jobs via the one call.

  • Parivesh Jain

    I was struggling with the last issue you have explained from last two days..
    gr8 help.. thanks

  • FOG

    Very value able post, I read the whole story when I start reading it.
    http://www.ourfog.com

  • http://meta64.com/wclayf Clay Ferguson

    Thanks for this awesome post Jim! I was struggling with why I wasn’t getting AOP advise calls when calling directly from my same class. That “Work Around” did the trick, but it’s also making me question whether Spring AOP is really worth using or not.

  • Pingback: Secrets of the Spring AOP Proxy | Life in USA

  • Binh Thanh Nguyen

    Thanks, nice post

{Offer-Title}

{Offer-PageContent}
Click Here