Spring AOP works in the context of a Spring container, so the service implementation that was defined in the previous session needs to be a Spring bean, I am defining it using the @Service annotation:
@Service public class DefaultInventoryService implements InventoryService{ ... }Now, I want to record the time taken for each of the method calls of my DefaultInventoryService - I am first going to modularize this as an "advice":
package org.bk.inventory.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AuditAdvice { private static Logger logger = LoggerFactory.getLogger(AuditAdvice.class); public void beforeMethod() { logger.info("before method"); } public void afterMethod() { logger.info("after method"); } public Object aroundMethod(ProceedingJoinPoint joinpoint) { try { long start = System.nanoTime(); Object result = joinpoint.proceed(); long end = System.nanoTime(); logger.info(String.format("%s took %d ns", joinpoint.getSignature(), (end - start))); return result; } catch (Throwable e) { throw new RuntimeException(e); } } }
This advice is expected to capture the time taken by the methods in DefaultInventoryService. So now to wire this advice to the DefaultInventoryService spring bean:
<bean id="auditAspect" class="org.bk.inventory.aspect.AuditAdvice" /> <aop:config> <aop:aspect ref="auditAspect"> <aop:pointcut id="serviceMethods" expression="execution(* org.bk.inventory.service.*.*(..))" /> <aop:before pointcut-ref="serviceMethods" method="beforeMethod" /> <aop:around pointcut-ref="serviceMethods" method="aroundMethod" /> <aop:after-returning pointcut-ref="serviceMethods" method="afterMethod" /> </aop:aspect> </aop:config>
This works by first defining the "pointcut" - the places(in this example, the service methods) to add the cross cutting concern(capturing the method execution time in this example) to. Here I have defined it using a pointcut expression -
execution(* org.bk.inventory.service.*.*(..)), which is essentially selecting all methods of all the types in the org.bk.inventory.service package. Once the pointcut is defined, it defines what needs to be done around the pointcut(the advice), using the expression:
<aop:around pointcut-ref="serviceMethods" method="aroundMethod" />This basically says, that around every method of any service type, execute the aroundMethod of AspectAdvice that was defined earlier. Now, if the service methods are executed, I would see the advice getting invoked during the method execution, the following is a sample output if DefaultInventoryService, createInventory method is called:
org.bk.inventory.service.InventoryService - Create Inventory called org.bk.inventory.aspect.AuditAdvice - Inventory org.bk.inventory.service.InventoryService.create(Inventory) took 82492 nsSpring's AOP implementation works by generating a dynamic proxy at runtime for all the target beans, based on the defined pointcut.
Links to all sessions on AOP:
AOP Session 1 - Decorator Pattern using Java Dynamic Proxies
AOP Session 2 - Using Spring AOP - xml based configuration
AOP Session 3 - Using Spring AOP - @AspectJ based configuration - with/without compile time weaving
AOP Session 4 - Native AspectJ with compile time weaving
AOP Session 5 - Comprehensive Example
No comments:
Post a Comment