Showing posts with label aop-pointcut. Show all posts
Showing posts with label aop-pointcut. Show all posts

Sunday, March 20, 2011

Implementing @Around advice

To get pre and post processing of calling any function, its good to implement @Around advice.

Consider the following Aspect with around advice:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.util.StopWatch;

@Aspect
public class ProfilingAspect {

@Around("execution(* *(..))")
public Object profile(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch watch = new StopWatch();
watch.start(joinPoint.getSignature().getName());
try {
return joinPoint.proceed(); //calling the target method
}
catch(Exception e) {
throw e;
}
finally {
watch.stop();
System.out.println(watch.prettyPrint());
}
}
}

 

Corresponding config file:



<aop:aspectj-autoproxy />

<bean id="profilingAspect" class="ex7.ProfilingAspect" />
<!--some service class -->
<bean id="customerService" class="service.CustomerServiceImpl" />

Exception handling with AOP

The throws advice is executed when a method throws an exception.

Handling exception by this method saves us from writing repeating try-catch block again and again.

Consider the following java code:

//interface with method throwing exception
public interface BusinessInterface {

public void someBusinessMethod() throws BusinessException;

}
//class implementing it
import org.springframework.jdbc.BadSqlGrammarException;

public class BusinessComponent implements BusinessInterface {

public void someBusinessMethod() throws BusinessException {
//we are raising a different exception to see the aspect coming into action
//assume that you are connecting to the database and something goes wrong
throw new BadSqlGrammarException("","",null);
}
}


So now this business logic may throw exception, and it will be handled by Aspect.


So we have to write handler for this:


import java.util.Locale;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;

@Aspect
public class ExceptionHandler implements MessageSourceAware {

private MessageSource messageSource;

@Override
public void setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
}

@AfterThrowing(pointcut="execution(* someBusinessMethod(..))", throwing="ex")
public void handleException(JoinPoint jp, RuntimeException ex) throws Throwable {
System.out.println("Routine exception handling code here.");
System.out.println("Let's see who has raised an exception!");
System.out.println("===================================");
System.out.println(jp.getSignature().getName());
System.out.println("===================================");
throw new BusinessException(messageSource.getMessage(jp.getSignature().getName(), null, Locale.getDefault()));
}
}


Now if we want pre and post analysis of method, @Around advice will be handy for this.


Corresponding config file:



<aop:aspectj-autoproxy />

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="ex6/messages" />
</bean>

<bean id="exceptionHandler" class="com.xxxx.ExceptionHandler" />

<bean id="businessComponent" class="com.xxxx.BusinessComponent" />

Implementing @After and @AfterReturning advice

As we have done @Before, till now, it is also similar to that.

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class LoggingAspect {

@After("bean(*Service)")
public void log(JoinPoint joinPoint) {
System.out.println("log advice got executed after call to method : "+joinPoint.getSignature().getName());
}

@AfterReturning(pointcut="execution(* balance(..)) && args(acno)", returning="balance")
public void validate(JoinPoint joinPoint, long acno, double balance) {
System.out.println("validate advice called after successful return from balance method");
System.out.println("acno passed was "+acno+" and the balance returned was "+balance);
}
}



Spring config file :


<aop:aspectj-autoproxy />

<bean id="loggingAspect" class="ex5.LoggingAspect" />

<bean id="orderService" class="service.OrderServiceImpl" />

<bean id="customerService" class="service.CustomerServiceImpl" />

Named pointcut expression

Sometimes it happens that we may need same pointcut at multiple places. But since pointcut expressions are lengthy, it will be good if instead of repeating we can give a logical name to that pointcut and refer to it by logical name.

So for this we have to first create pointcut config :

package com.xxxx;
//
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class PointcutConfig {

@Pointcut("execution(public * service.*.*(..))") //This is a pointcut expression
public void serviceComponents() {} //This is a name given to the pointcut expression

@Pointcut("execution(* apply*(..))")
public void applyMethods() {}

}



Note that we @Aspect and @Pointcut annotations above.


When we write our own aspect we can simply refer to these method names in pointcut-config now:


import java.util.Date;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect {

@Before("com.xxxx.PointcutConfig.applyMethods()")
public void log(JoinPoint joinPoint) {
System.out.println("log advice executed for method : "+joinPoint.getSignature().getName());
}

@Before("com.xxxx.PointcutConfig.serviceComponents()")
public void timeLog(JoinPoint joinPoint) {
System.out.println("request for method : "+joinPoint.getSignature().getName()+" occurred at "+new Date());
}
}


In the config file, we have to define both beans:


<aop:aspectj-autoproxy />

<bean id="pointcutConfig" class="ex4.PointcutConfig" />

<bean id="loggingAspect" class="ex4.LoggingAspect" />

<bean class="service.OrderServiceImpl" />

<bean class="service.CustomerServiceImpl" />

Binding parameters to advice

A joinpoint object provides all the details required by the advice to perform any kind of operation.

Suppose we have to validate an order, and so we are writing our own aspect to get argument from pointcut - expression and perform validation. Example:

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import service.Order;

@Aspect
public class OrderValidator {

@Before("execution(* placeOrder(..)) && args(order)")
public void validateOrder(Order order) {
//some order validation logic here
System.out.println("Just checking it out!");
}
}

In the config file we write:


<aop:aspectj-autoproxy />

<bean class="ex3.OrderValidator" />

<bean class="service.OrderServiceImpl" />


Pointcut expression

The most typical pointcut expressions are used to match a number of methods by their signatures. A common method based pointcut expression is something like

PCD(<method scope> <return type> <fully qualified class name>.*(arguments))


  1. PCD - PCD is pointcut designators. Spring AOP supports following pointcut expression -
    -- execution, with, this,target, args
    --Spring AOP also supports an addition PCD - "bean"
    --Of these, execution is most common
  2. method scope: Advice will be applied to all the methods having this scope. For e.g., public, private, etc. Please note that Spring AOP only supports advising public methods.
  3. return type: Advice will be applied to all the methods having this return type.
  4. fully qualified class name: Advice will be applied to all the methods of this type. If the class and advice are in the same package then package name is not required
  5. arguments: You can also filter the method names based on the types. Two dots(..) means any number and type of parameters.

Also these expressions can be chained to create composite pointcuts : && (and), || (or) , ! (not)


Some examples


the execution of any public method:
execution(public * *(..))

the execution of any method with a name beginning with “set”:
execution(* set*(..))

the execution of any method defined by the MyService interface
execution(* com.xyz.service.MyService.*(..))

the execution of any method defined in the service package:
execution(* com.xyz.service.*.*(..))

the execution of any method defined in the service package or a sub-package:
execution(* com.xyz.service..*.*(..))

any join point (method execution only in Spring AOP) WITHIN the service package:
within(com.xyz.service.*)

any join point (method execution only in Spring AOP) within the service package or a sub-package:
within(com.xyz.service..*)

any join point (method execution only in Spring AOP) where the proxy implements the AccountService interface:
this(com.xyz.service.AccountService)

any join point (method execution only in Spring AOP) where the target object implements the AccountService interface:
target(com.xyz.service.AccountService)

any join point (method execution only in Spring AOP) which takes a single parameter, and where the argument passed at runtime is Serializable:
args(java.io.Serializable)

Spring : Advice and its type

Any functionality that exists in an application, but cannot be added in a desirable way is called a cross-cutting concern.

That cross-cutting concern is called aspect-oriented programming (AOP). It deals with the functionality in applications that cannot be efficiently implemented with pure object-oriented techniques.

One of the core features of AOP frameworks is implementing cross-cutting concerns once and reusing them in different places and in different applications. In AOP jargon, the implementation of a cross-cutting concern is called an advice.

AOP frameworks allow you to define which advice is applied to which methods

Spring AOP supports following types of advices
Joinpoint is the point of execution of application, like method.
Spring AOP supports four advice types that each represents a specific scenario for advice implementations:
  • Around advice: Controls the execution of a join point. This type is ideal for advice that needs to control the execution of the method on the target object.
  • Before advice: Is executed before the execution of a join point. This type is ideal for advice that needs to performan action before the execution of the method on the target object.
  • After advice: Is executed after the execution of a join point. This type is ideal for advice that needs to perform an action after the execution of the method on the target object.
  • Throws advice: Is executed after the execution of a join point if an exception is thrown. This type is ideal for advice that needs to performan action when the execution of the method on the target object has thrown an exception.

Using annotation for configuring advices

We again take example of before advice.

Now we add @Aspect at the bean level. But on the method of the Aspect class, we can have annotations depending on what type of method or better advice they are. For before type advice we have @Before annotation.

Creating the aspect class


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect {

//TODO: Try other pointcut expressions also as mentioned in slide no. 203-207
@Before("execution(public * apply*(..))")
public void log(JoinPoint joinPoint) {
System.out.println("common logging code executed for : "+joinPoint);
}
}


Now the bean class is quite cleaner, as we are annotation:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
>

<aop:aspectj-autoproxy />

<bean id="customerService" class="service.CustomerServiceImpl" />

<bean id="loggingAspect" class="ex2.LoggingAspect" />

</beans>


Here we are simply logging a simple text before entering the methods. Consider the case when we want to print about arguments.


This is where JoinPoint object comes into picture.


More about JoinPoint Object


Changing the before advice to take care of arguments , etc of the methods.


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class LoggingAspect2 {

@Before("execution(public * apply*(..))")
public void log(JoinPoint joinPoint) {
Object proxyObject = joinPoint.getThis();
Object targetBean = joinPoint.getTarget();
Object[] args = joinPoint.getArgs();
Signature signature = joinPoint.getSignature();
//some logging code here
}
}



In the above xml file just change the class name of LoggingAspect to LoggingAspect2.


As the names of the method suggest :



  • this : The current executing object that has been intercepted

  • target : The target of the execution (typically our object)

  • args -  method args

  • signature - method signation of the joinpoint

One of the reason why aspectJ was adopted by the spring was because of v.powerful and easy to learn pointcut expression, which define where our aspects will execute.

Spring : Xml style configuration for pointcuts (Before advice)

The Aspect Class:

import org.aspectj.lang.JoinPoint;

//This is an Aspect class
public class LoggingAspect {

//This is an advice.
//Pointcut means where will this advice be applied.
public void log(JoinPoint joinPoint) {
System.out.println("common logging code executed for : "+joinPoint);
}

}

The configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
>

<!-- Tells the container we will be using AspectJ.
Also tells the container to use the proxy approach for executing aspects -->
<aop:aspectj-autoproxy />

<bean id="customerService" class="service.CustomerServiceImpl" />

<bean id="loggingAspect" class="com.xxxx.LoggingAspect" />

<!-- Aop config start -->

<aop:config>
<aop:pointcut expression="execution(public * apply*(..))" id="pointcut1" />
<aop:aspect ref="loggingAspect">
<aop:before method="log" pointcut-ref="pointcut1" />
</aop:aspect>
</aop:config>

</beans>


Note that we are using "aop" namespace in the xml to configure it to aspect class.

 


 

AOP : Terminology

Aspect-Oriented Programming (AOP) complements Object-Oriented Programming (OOP) by providing another way of thinking about program structure. The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the aspect. Aspects enable the modularization of concerns such as transaction management that cut across multiple types and objects.
 

AOP concepts:

Aspect: a modularization of a concern that cuts across multiple classes. Transaction management is a good example of a crosscutting concern in J2EE applications. In my words: a trigger which can affect the multiple classes a one point….
Aspects are implemented using Spring as Advisors or Interceptors.

Join point: a point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution.

Advice: action taken by an aspect at a particular join point. Different types of advice include “around,” “before” and “after” advice. (Advice types are discussed below.) In my words : the action to be taken at the point. See here for type of advices.

Pointcut: Pointcuts are the expression which identify where an advice should apply. Its a predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name). The concept of join points as matched by pointcut expressions is central to AOP, and Spring uses the AspectJ pointcut expression language by default

Introduction: declaring additional methods or fields on behalf of a type. Spring AOP allows you to introduce new interfaces (and a corresponding implementation) to any advised object. For example, you could use an introduction to make a bean implement an IsModified interface, to simplify caching. (An introduction is known as an inter-type declaration in the AspectJ community.)
Target object: object being advised by one or more aspects. Also referred to as the advised object. Since Spring AOP is implemented using runtime proxies, this object will always be a proxied object.
AOP proxy: an object created by the AOP framework in order to implement the aspect contracts (advise method executions and so on). In the Spring Framework, an AOP proxy will be a JDK dynamic proxy or a CGLIB proxy.

Chitika