java - Spring AOP reentrant aspects -
is possible create reentrant aspects spring aop (or aspectj)?
here example:
@log public int calcfibonacci(int n) { if(n <= 1) { homecoming n; } else { homecoming calcfibonacci(n - 1) + calcfibonacci(n - 2); } }
and aspect:
@aspect public class loggingaspect { @around("@annotation(log)") public object measure(proceedingjoinpoint pjp, log log) throws throwable { // log relevant info log annotation , pjp ... homecoming pjp.proceed(); }
}
now i'd know how many times calcfibonacci called (counting in recurrent calls).
is there way accomplish this?
okay, cannot solve elegantly in spring aop - see first remark andrei stefan's answer. if in aop application code needs know aspect's existence or phone call aspect-related code, bad design , anti-aop. thus, here have aspectj solution you.
first of all, in aspectj there more execution()
pointcuts, e.g. call()
. thus, counting joinpoints annotated @log
yield result twice big actual number of recursive calls calcfibonacci(int)
. because of this, pointcut should not just
@annotation(log)
but
class="lang-java prettyprint-override">execution(* *(..)) && @annotation(log)
actually, still not plenty because if multiple methods contain @log
annotations? should calls counted? no, calcfibonacci(int)
! should restrict "fibonacci phone call counter" more like:
execution(* *..application.calcfibonacci(int)) && @annotation(log)
here compileable sample code:
annotation:
package de.scrum_master.app; import java.lang.annotation.retention; import java.lang.annotation.retentionpolicy; @retention(retentionpolicy.runtime) public @interface log {}
application recursive fibonacci method:
package de.scrum_master.app; public class application { public static void main(string[] args) { int fibonaccinumber = 6; system.out.println("fibonacci #" + fibonaccinumber + " = " + new application().calcfibonacci(fibonaccinumber)); } @log public int calcfibonacci(int n) { homecoming n <= 1 ? n : calcfibonacci(n - 1) + calcfibonacci(n - 2); } }
aspect, version 1:
package de.scrum_master.aspect; import org.aspectj.lang.joinpoint; import org.aspectj.lang.annotation.aspect; import org.aspectj.lang.annotation.before; import de.scrum_master.app.log; @aspect public class loggingaspect { int count = 0; @before("execution(* *..application.calcfibonacci(int)) && @annotation(log)") public void measure(joinpoint thisjoinpoint, log log) { system.out.println(thisjoinpoint + " - " + ++count); } }
output, version 1:
class="lang-none prettyprint-override">execution(int de.scrum_master.app.application.calcfibonacci(int)) - 1 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 2 (...) execution(int de.scrum_master.app.application.calcfibonacci(int)) - 24 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 25 fibonacci #6 = 8
now, if phone call fibonacci method twice?
int fibonaccinumber = 6; system.out.println("fibonacci #" + fibonaccinumber + " = " + new application().calcfibonacci(fibonaccinumber)); fibonaccinumber = 4; system.out.println("fibonacci #" + fibonaccinumber + " = " + new application().calcfibonacci(fibonaccinumber));
class="lang-none prettyprint-override">execution(int de.scrum_master.app.application.calcfibonacci(int)) - 1 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 2 (...) execution(int de.scrum_master.app.application.calcfibonacci(int)) - 24 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 25 fibonacci #6 = 8 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 26 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 27 (...) execution(int de.scrum_master.app.application.calcfibonacci(int)) - 33 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 34 fibonacci #4 = 3
uh-oh!!!
we need either reset counter in between calls (and create sure whole thing thread-safe using threadlocal
or so) or utilize aspect instantiation per command flow instead of singleton aspect, utilize here fun of it:
aspect, version 2:
class="lang-java prettyprint-override">package de.scrum_master.aspect; import org.aspectj.lang.joinpoint; import org.aspectj.lang.annotation.aspect; import org.aspectj.lang.annotation.before; import de.scrum_master.app.log; @aspect("percflow(execution(* *.calcfibonacci(int)) && !cflowbelow(execution(* *.calcfibonacci(int))))") public class loggingaspect { int count = 0; @before("execution(* *.calcfibonacci(int)) && @annotation(log)") public void measure(joinpoint thisjoinpoint, log log) { system.out.println(thisjoinpoint + " - " + ++count); } }
note:
i have shortened bundle , class specification*
in order create source code more readable. can utilize de.scrum_master.app.application
or abbreviation of in order avoid collisions similar class/method names. the @aspect
annotation had parameter says: "create 1 instance per execution of fibonacci method, exclude recursive ones." output, version 2:
class="lang-none prettyprint-override">execution(int de.scrum_master.app.application.calcfibonacci(int)) - 1 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 2 (..) execution(int de.scrum_master.app.application.calcfibonacci(int)) - 24 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 25 fibonacci #6 = 8 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 1 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 2 (..) execution(int de.scrum_master.app.application.calcfibonacci(int)) - 8 execution(int de.scrum_master.app.application.calcfibonacci(int)) - 9 fibonacci #4 = 3
now, looks much better. :)))
enjoy!
java spring aspectj spring-aop aspect
No comments:
Post a Comment