RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Implement Logging as an Aspect Using Spring's AOP Framework : Page 2

Aspect-oriented programming (AOP) enables you to write code for a crosscutting functionality and then apply it declaratively to existing code. Logging is a prime candidate for implementation as an aspect, and Spring offers the AOP framework to get it done.


Spring as an AOP Framework

Spring uses a proxy-based approach to tie aspects into the object model. That is, Spring intercepts all method invocations to the aspected objects and then proxies the method invocations to the intended objects. So, an application makes a method call to a business object, Spring intercepts that call, applies the weaved crosscutting aspect, and then makes a method call to the intended business object. It is just like the EJB framework, where the EJB Container intercepts calls to the EJB component, applies the intended crosscutting behavior (like security check, transaction, etc.), and then invokes the intended EJB object. It defines and applies the aspects using a XML configuration file.

Configuring Logging as AOP

Listing 1 shows the configuration file that Spring uses to gel together components and services:

Listing 1. Example XML Configuration File for Spring

<bean id="maintenanceServiceBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces"> <value>IMaintenanceService</value> </property> <property name="target"> <ref bean="maintenanceServiceImpl"/> </property> <property name="interceptorNames"> <list> <value>loggingInterceptor</value> </list> </property> </bean> <bean id=" maintenanceServiceImpl " class="MaintenanceService"> <bean id=" loggingInterceptor" class="LoggingInterceptor"/>

Spring's 'built-in' AOP infrastructure is defined by the org.springframework.aop.* packages. Spring supports the concept of a FactoryBean, a special type of bean that is returned as a factory result rather than just a plain newInstance() call on the class provided. That means the example given in Listing 1 will not produce an instance of ProxyFactoryBean, but Spring consults with the ProxyFactoryBean object and asks for the maintenanceServiceBean object. Why is all of this important? Because this FactoryBean concept is how Spring wraps beans and then creates a proxy for the bean (using some internal tool such as dynamic proxies, CGLIB, etc.) that executes some advice on method calls when the pointcut says the method is a joinpoint (assuming a pointcut is defined). A joinpoint is a point during the execution of a program such as method invocation or an exception being thrown. That means in this example when the container is asked for a maintenanceServiceBean object, it will return an object that intercepts calls to the target maintenanceServiceImpl object, giving LoggingInterceptor a shot at handling method calls first. Once LoggingInterceptor is finished, control is returned to maintenanceServiceImpl to perform the original task.

The interceptorNames property is how the proxy factory bean finds out which advisors or advice objects need to be applied to the proxied bean. Order is important in this property's list—the order in which the advisors or advice objects are entered in the list defines the order they will be invoked when entering and exiting the bean. So in Listing 1, the loggingInterceptor is the advised object, which needs to be applied to the proxied maintenanceServiceBean.

Listing 2 shows the code for the LoggingInterceptor class:

Listing 2. The LoggingInterceptor Class

import java.lang.reflect.Method; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.aop.AfterReturningAdvice; import org.springframework.aop.MethodBeforeAdvice; import org.springframework.aop.ThrowsAdvice; public class LoggingInterceptor implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice{ private static Log log = null; public LoggingInterceptor(){ } public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { log = LogFactory.getLog(arg2.getClass()); log.info("Beginning method: "+arg0.getName()); } public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { log = LogFactory.getLog(arg3.getClass()); log.info("Ending method: "+arg1.getName()); } public void afterThrowing(Method m, Object[] args, Object target, Throwable ex) { log = LogFactory.getLog(target.getClass()); log.info("Exception in method: "+m.getName()+" Exception is: "+ex.getMessage()); } }

The LoggingInterceptor class implements three interfaces of the Spring AOP framework: MethodBeforeAdvice, AfterReturningAdvice, and ThrowsAdvice. The MethodBeforeAdvice interface is implemented by advice, which needs to be fired before the target method is invoked. The interface has a void before (Method arg0, Object [] arg1, Object arg2) throws Throwable method, which needs to be implemented. The code inside the before method gets executed before the target method is executed. So, Listing 2 includes the appropriate code to log the method call.

Similarly, the AfterReturningAdvice interface is implemented by advice, which needs to be fired after the target method is executed. This interface has a void afterReturning (Object arg0, Method arg1, Object [] arg2, Object arg3) throws Throwable method, which gets executed after the target method is executed.

Lastly, the ThrowsAdvice interface is implemented by advices that need to be fired when the target method throws an exception. It has a void afterThrowing(Method m, Object[] args, Object target, Throwable ex) method that gets executed when the target method throws an exception.

Since the general logging functionality involves tracing entry into a method, exit from the method, and exception, the LoggingInterceptor class implements the above three interfaces to carry out these tasks.

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date