Book Image

Spring 2.5 Aspect Oriented Programming

Book Image

Spring 2.5 Aspect Oriented Programming

Overview of this book

Developing powerful web applications with clean, manageable code makes the maintenance process much easier. Aspect-Oriented Programming (AOP) is the easiest and quickest way to achieve such results. Spring is the only Java framework to offer AOP features. The combined power of Spring and AOP gives a powerful and flexible platform to develop and maintain feature-rich web applications quickly. This book will help you to write clean, manageable code for your Java applications quickly, utilizing the combined power of Spring and AOP. You will master the concepts of AOP by developing several real-life AOP-based applications with the Spring Framework, implementing the basic components of Spring AOP: Advice, Joinpoint, Pointcut, and Advisor. This book will teach you everything you need to know to use AOP with Spring. It starts by explaining the AOP features of Spring and then moves ahead with configuring Spring AOP and using its core classes, with lot of examples. It moves on to explain the AspectJ support in Spring. Then you will develop a three-layered example web application designed with Domain-Driven Design (DDD) and built with Test-Driven Development methodology using the full potential of AOP for security, concurrency, caching, and transactions.
Table of Contents (13 chapters)

What Spring provides in terms of AOP


The main aim of Spring AOP is to allow the realization of JEE functionalities in the simplest manner and without being intrusive. With this aim, it allows the use of a subset of AOP functionalities in a simple and intuitive way (introduced since version 1.x, and in version 2.x with new integrations with AspectJ).

In order to achieve this aim, since version 1.x, Spring has implemented the specifications of the AOP alliance. This is a joint effort between representatives of many open-source AOP projects, including Rod Johnson of Spring, to define a standard set of interfaces for AOP implementations.

In Spring AOP, an aspect is represented by an instance of a class that implements the Advisor interface. There are two subinterfaces of Advisor: IntroductionAdvisor and PointcutAdvisor. The PointcutAdvisor interface is implemented by all Advisors that use pointcuts to control the applicability of advice to joinpoints.

In Spring, introductions are treated as special kinds of advice. Using the IntroductionAdvisor interface, you can control those classes to which an introduction applies.

The core of Spring AOP is based around proxies. There are two ways of using proxies: programmatic modality and declarative modality.

The former consists of using a ProxyFactory to create a proxy of the class on which you want to apply an aspect. After creating the proxy, you use the ProxyFactory to weave all the aspects you want to use on the object.

The ProxyFactory class controls the weaving and proxy creation process in Spring.

Using the ProxyFactory class, you control which aspects you want to weave into the proxy. You can weave only an aspect, that is, advice combined with a pointcut.

However, in some cases you want an advice to apply to the invocation of all methods in a class, not just a selection. For this reason, the ProxyFactory class provides the addAdvice() method. Internally, addAdvice() wraps the advice you pass it in an instance of DefaultPointcutAdvisor, and configures it with a pointcut that includes all methods by default.

Programmatic way

This is an example of class that implements the MethodBeforeAdvice to perform a crosscutting functionality before the method of the target class.

Before advice

Before advice is performed before the invocation of the method.

Let us see an example that shows the usage of before advice, with a class that implements the MethodBeforeAdvice, and has a main method for testing.

package org.springaop.chapter.one;
import java.lang.reflect.Method;
import org.springaop.target.Hello;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
public class BeforeAdvice implements MethodBeforeAdvice{
public static void main(String[] args) {
//target class
Hello target = new Hello();
// create the proxy
ProxyFactory pf = new ProxyFactory();
// add advice
pf.addAdvice(new BeforeAdvice());
// setTarget
Spring AOPbefore advice methodpf.setTarget(target);
Hello proxy = (Hello) pf.getProxy();
proxy.greeting();
}
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println("Good morning");
}
}
public class Hello {
public void greeting(){
System.out.println("reader");
}
}

The result will be:

After returning advice

After returning advice is performed after the invocation of the method.

package org.springaop.chapter.one;
import java.lang.reflect.Method;
import org.springaop.target.Hello;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.framework.ProxyFactory;
public class AfterRetuningAdvice implements AfterReturningAdvice {
public static void main(String[] args) {
// target class
Hello target = new Hello();
// create the proxy
ProxyFactory pf = new ProxyFactory();
// add advice
pf.addAdvice(new AfterRetuningAdvice());
// setTarget
pf.setTarget(target);
Hello proxy = (Hello) pf.getProxy();
proxy.greeting();
}
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println(",this is a afterReturningAdvice message");
}
}
public class Hello {
public void greeting(){
System.out.println("reader");
}
}

The result will be:

Around advice

This is the Hello target class on which we want to apply an around advice. It is called before the method and controls its invocation.

public class Hello {
public void greeting(){
System.out.println("reader");
}
}

This is the advice that must be applied around the performed method; as we can see that the invocation of the method occurs with invocation.proceed.

package org.springaop.chapter.one;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class MethodDecorator implements MethodInterceptor{
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.print("Hello ");
Object retVal = invocation.proceed();
System.out.println("this is aop !");
return retVal;
}
}

This is the class where, through the ProxyFactory, we give the advice to apply. But, in the case of the MethodDecorator, it is an around advice.

package org.springaop.chapter.one;
import org.springaop.target.Hello;
import org.springframework.aop.framework.ProxyFactory;
public class AroundAdvice {
public static void main(String[] args) {
//target class
Hello target = new Hello();
// create the proxy
ProxyFactory pf = new ProxyFactory();
// add advice
pf.addAdvice(new MethodDecorator());
// setTarget
pf.setTarget(target);
Hello proxy = (Hello) pf.getProxy();
proxy.greeting();
}
}

The result will be:

After throwing advice

This advice is performed only if the method on which the advice is applied throws an exception.

This is a class that intentionally throws an exception in every method; the exceptions are of different types.

package org.springaop.target;
public class ExceptionTarget {
public void errorMethod() throws Exception {
throw new Exception("Fake exception");
}
public void otherErrorMethod() throws IllegalArgumentException {
throw new NullPointerException("Other Fake exception");
}
}

This is the code to try it:

package org.springaop.chapter.one;
import java.lang.reflect.Method;
import org.springaop.target.ExceptionTarget;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.aop.framework.ProxyFactory;
public class ThrowsAdviceClass implements ThrowsAdvice {
public static void main(String[] args) {
//target class
ExceptionTarget errorBean = new ExceptionTarget();
// create the proxy
ProxyFactory pf = new ProxyFactory();
// add advice
pf.addAdvice(new ThrowsAdviceClass());
// setTarget
pf.setTarget(errorBean);
ExceptionTarget proxy = (ExceptionTarget) pf.getProxy();
try {
proxy.errorMethod();
} catch (Exception ignored) {
}
try {
proxy.otherErrorMethod();
} catch (Exception ignored) {
}
}
public void afterThrowing(Exception ex) throws Throwable {
System.out.println("+++");
System.out.println("Exception Capture:"+ex.getClass().getName());
System.out.println("+++\n");
}
public void afterThrowing(Method method, Object[] args,
Object target, NullPointerException ex) throws Throwable {
System.out.println("+++");
System.out.println("NullPointerException Capture: "+ex.getClass().getName());
System.out.println("Method: " + method.getName());
System.out.println("+++\n");
}
}

The result will be:

The old Spring XML way

Here we will see how to use the examples described previously, configuring the classes as Spring beans declared in XML file and using a ProxyFactoryBean.

<bean id="helloMatch" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<bean class="org.springaop.Hello"/>
</property>
<property name="interceptorNames">
<list>
<idref bean="helloBeforeAdvice"/>
<idref bean="helloAfterRetuningAdvicee"/>
</list>
</property>
</bean>
<bean id="helloBeforeAdvice" class="org.springaop.advice.BeforeAdvice"/>
<bean id="helloAfterRetuningAdvice" class="org.springaop.advice.AfterRetuningAdvice"/>

In the configuration of the example, we can see how a helloMatch is defined, which is in fact a ProxyFactoryBean that puts together the target object on which the crosscutting concern has to be applied, and the list of advice that contains the crosscutting functionalities. In this case, two of the advices are used in the programmatic modality and are applied at the target object as a reference in the list of interceptors that can be applied on the object.

It is an implementation of Spring FactoryBean that allows you to specify a bean to target and provides a set of advice and advisors for that bean that are eventually merged into an AOP proxy. Because you can use both advisor and advice with the ProxyFactoryBean, you can configure not only the advice declaratively, but the pointcuts as well.

In both modalities Spring uses internally two sorts of proxy: JDK proxy or CGLIB proxy.

The concept of an Advisor principally concerns Spring 1.x. We will see later how it can benefit by the syntax of the pointcuts of AspectJ.

From the 2.x version onwards, there is a closer integration or configuration based on AspectJ and its syntax, either through annotations or through schema-based configuration. In any case, it's always possible to use AOP in the classic way as in the 1.x version.

Spring is first of all an IoC Container, and so it allows using the components that implement the AOP as a simple bean, assembling them and obtaining the result of the AOP weaver through Proxy classes, as we previously described.

Instead, AspectJ provides a static implementation of AOP that is produced at compile time. Spring provides a dynamic implementation of AOP, as it is implemented through the creation and the use of proxy classes that permit the implementation of a chain of interceptors.

Obviously, a static implementation provides better performance, but requires greater knowledge and a compiler, whereas the dynamic implementation is easier to use and more accessible. It can be disabled from configuration and never requires anything different from the usual Java compiler.

Spring permits only method execution to be used as a joinpoint. So we can't use with Spring AOP all the features of AOP, but we can do so with AspectJ called by Spring. For example, we must use the support of AspectJ if we want to use as a joinpoint:

  • The invocations of constructors

  • Access to the domains of objects with the setter and getter

  • The initialization of an object

  • The initialization of an object with a calling super()

  • The execution inside a class with this()

  • The calling of a method

Therefore, the aspect can be normal Java classes with the annotation @Aspect, or configured using configuration XML.

The advices are seen as interceptors that maintain a chain of interceptors around the joinpoint.

Pointcuts are performed according to the matching of the AspectJ pointcut expression language, or according to regular expressions following the rules present since Spring 1.x.

This introduction clearly shows that Spring has a simplified pattern of the whole set of AOP features so that AOP can be used with no special editing and alterations to the bytecode. This would be necessary together with the use of AspectJ, if we wanted all the features of AOP as we will see in the rest of this book.