Announcement Announcement Module
Collapse
No announcement yet.
Mixed ordering of @Before and @After advices does not work Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Mixed ordering of @Before and @After advices does not work

    I have prepared an example of mixed AOP advices ordering which can demonstrate that ordering is not applied cross @Before and @After advices.

    Just run example.OrderingDemoTest
    To change ordering it is enough to play with numbers in example.aop.CheckPrecedence

    To see the problem, just uncomment the line with throw new RuntimeException in example.aop.CheckBeforeAspect

    As I have debugged the problem is in org.springframework.aop.aspectj.autoproxy.AspectJP recedenceComparator (code snippet):
    Code:
    		boolean oneOrOtherIsAfterAdvice =
    				(AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));
    		boolean oneOrOtherIsBeforeAdvice =
    				(AspectJAopUtils.isBeforeAdvice(advisor1) || AspectJAopUtils.isBeforeAdvice(advisor2));
    		if (oneOrOtherIsAfterAdvice && oneOrOtherIsBeforeAdvice) {
    			return NOT_COMPARABLE;
    		}
    So the question is:
    • is this the error or the intention? why this mixed Before-After ordering is disabled by extra code?
    • is there any workaround available to make such situation working other than implementing advices as @Around?

    Thank you if you bring some more light into this.

  • #2
    Sorry for replying so late to this thread, but I'm not sure I follow. What would you expect your sample to do in the case "throw new RuntimeException" is uncommented?

    Comment


    • #3
      Originally posted by Andrei Stefan View Post
      Sorry for replying so late to this thread, but I'm not sure I follow. What would you expect your sample to do in the case "throw new RuntimeException" is uncommented?
      Thank you for looking at my example project.
      The aim is to order aspects in such way that after throwing the RuntimeException in the @Before advice I would like the two of @After advices to be called, no matter if exception was thrown.
      When ordering is set correctly the @Before advice has lower precedence and thus it is "wrapped" into the @After advices, so these can be called normally also after throwing any exception.

      My finding is that such ordering (of mixed @Before and @After aspects) is disabled by extra code in AspectJPrecedenceComparator and I don't really understand if it is a bug or an intention and what is the reason of this intention alternatively.
      In such case the aspects are ordered naturally as they are configured as beans ignoring the Ordered interface or @Order annotation. When I switch the implementation of all advices to @Around everything works as expected.

      I have reported this problem also in Spring JIRA: https://jira.springsource.org/browse/SPR-9438
      You can find there a simplified example project, which is more straightforward to demonstrate this problem.

      Thank you for your help.

      Comment


      • #4
        There are two different things here:

        1. If you test the same configuration but taking out the @Configuration way of defining the beans (using XML configuration, for example), both @After aspects get called without problems even if the @Before aspect throws an exception. So, there seems to be a difference between execution with @Configuration and without.

        2. I don't think you can have ordering at both @After and @Before aspects simply because Before always executes before the method and After always executes after the method runs. You can have ordering on the same type of aspect (meaning ordering between two Befores and ordering between two Afters), but you can't put an order between two Befores and two Afters (Before always gets executed before and After always gets executed after).
        Last edited by Andrei Stefan; Jun 14th, 2012, 06:55 AM.

        Comment


        • #5
          Please, find attached the updated version of JIRA example project - the version with XML configuration instead of @Configuration

          Test is still failing until you move the definition of "B" one line lower either in XML or in @Configuration.

          Well, strictly taken, the ordering of advices could mean the order in which they are executed, so from this point of view the ordering between @Before and @After has no big sense.

          But if you go deeper into nature of AOP and if you put a breakpoint into the target method T.callMethod, which is wrapped by 3 advices, you can clearly see from stacktrace the advices and the "order" in which they are wrapped into each other. From this point of view the ordering of advices is just setting the precedence in which the advices are wrapped around the target method (or the distance from target, if you like) and here we have no limitations in ordering of advices. And it perfectly conforms the way how the Ordered interface and @Order annotations are used in Spring framework.

          I have come to this problem from a real situation: I have a method with business logic
          - before execution there is a check which throws an exception in some business cases
          - after execution I need to collect some statistics, no matter if method was successfully called or not, or if it had thrown the exception or not, and no matter if the exception was thrown from target method itself or from the @Before advice. I need to collects statistics just simply because there was a try to call the target method. I think it makes sense logically and fits also into AOP concept.

          So after some debugging I found a code snippet in org.springframework.aop.aspectj.autoproxy.AspectJP recedenceComparator (see above in my original post) which is evaluating such situation - compare ordering of @Before and @After aspect - as NOT_COMPARABLE and thus leaving the precedence of such advices natural as defined in XML or @Configuration - which is not much predictable generally.

          This limitation is not mentioned in documentation and so the question is: is this an error or intention? Or another question: what is the meaning of aspects ordering? Is it strictly taken only the order in which they are executed or is it setting the precedence (distance from target method) ?

          Comment


          • #6
            If you put an order between Before and After then you simply ignore the very meaning and purpose of those advices, I already explained this in my previous reply. What you are looking for here is an Around advice.

            Comment


            • #7
              What the order of aspects really means?

              I try to bring some light into this problem; because here is some kind of misunderstanding.

              The real question here is What the order of aspects really means?
              Does it means order of executing of aspect's code? From posts above I could say Andrei thinks that yes. But I must say not exactly!
              Aspects are like as onion layers and target is in the core. Aspect which wraps all other aspects around same target has highest precedence and last aspect with lowest precedence wraps just target. Order means just that, independently of aspect's type. Doesn't matter if type of aspect is BeforeAdvice or AfterAdvice, a fact is that aspect with BeforeAdvice can wraps aspect with AfterAdvice and vice versa. That is exactly meaning of order of aspects!


              Now I would like to explain how the order of aspects affect execution of advices. Look at the following figure:
              Attachment
              There are two pseudo sequential diagrams and each represents two calls. For now focus just on first call:

              1st - normal flow (without exception)
              On the left diagram are aspects ordered that before is first (has higher precedence than after) and on the right diagram are aspects ordered vice versa.
              The incoming call from caller in left diagram reach aspect before and immediately executes BeforeAdvice but on right diagram the call reaches aspect after which isn't executed because is of it's type. Then we move to the next aspect according to order (deeper layer), the calling on left diagram reaches aspect after wich also isn't executed; but on right diagram was reached before aspect and that one is executed.
              In next step is executed target on both sides. Now, when we are following the response of the 1st call, we can se that the response reach aspect after on left side and executed AfterAdvice, while on right side is reached aspect before which isn't executed (because of it's type). In next step the response reaches aspect before (not executed) on left diagram and it reaches aspect after (and executed) on right diagram. Finally the calls finished when response returns to caller on both diagrams.

              I hope that you was able to follow my thoughts, because it's important to understand this issue. We went trough the first call and we where see that code was executed in same order on both diagrams (BeforeAdvice -> Target -> AfterAdvice) - independently of order of aspects. If we understand the order of aspects same way, we can see that AfterAdvice can be never called before BeforeAdvice.
              So, why missus think that order of before and after aspects depends?

              2st - flow when before aspect throws an exception
              Now we try to focus on second call. Imagine that before aspect can throw and exception. If you was able follow my thoughts during first call, then you can easily figure out that the result is different. Order of aspects doesn't affect the order of execution of advices, but it affect if the execution of AfterAdvice is executed or not.


              I was very surprised when missus point on extra code in spring framework which disable ordering before and after aspects. It looks that author of that code overlooked the case when before aspect throws an exception. I just thought that before and after aspects implemented in spring are unreliable and I preferred to use always around aspects. But now when missus found the very essence of the problem I suggest to fix it. According these facts only before and afterReturn aspects are truly independent of aspects oder.
              Attached Files
              Last edited by profiprog; Jun 16th, 2012, 12:31 PM. Reason: attachement disapears

              Comment


              • #8
                spring advice ordering

                Found some nice examples on spring advice reordering
                here

                Comment


                • #9
                  Thanks for nice examples, but our case is not simulated there.

                  There is @Before farther from joinpoint that @AfterThrowing (defined by ordering) - so you never get an exception from @Before aspect in @AfterThrowing aspect because the @Before is executed in "outer layer" from joinpoint.

                  We wanted to achieve the opposite, throw an exception in @Before (in some business case) and catch it in @AfterThrowing aspect, no matter if thrown from @Before or joinpoint itself, which is proper requirement but not achievable by ordering of @Before and @After aspects, finally I had to use an @Around aspect where the ordering is applied.

                  You can play with my examples and see also the Spring issue I have raised: https://jira.springsource.org/browse/SPR-9438

                  Comment

                  Working...
                  X