Showing posts with label AspectJ. Show all posts
Showing posts with label AspectJ. Show all posts

Thursday, January 24, 2013

Aspectj pointcut expression based on annotation on types/methods

Consider two classes, one with annotation applied on the type and one with annotation on a method:

@CustomAnnotation
public class Class1 {
 
 public void method11(){}

 public void method12(){}
}

public class Class2 {
 
 @CustomAnnotation
 public void method21(){}
 
 public void method22(){}

}


I had to write a Aspectj pointcut which selects the methods on classes where the CustomAnnotation is applied on types - methods of Class1 above. My first gut feel was to write an aspect along these lines:
@Pointcut("execution(@CustomAnnotation  * *.*(..))")
public void methodsInAnnotatedTypes(){}

This pointcut is wrong though, as it ends up selecting methods of Class2.

The reason is this, the pointcut expression signature for execution pointcut type is the following(this is from the Spring documentation site available here):

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?.name-pattern(param-pattern) throws-pattern?)

To select the methods based on annotation on the type, I have to add the annotation to the declaring-type-pattern above like the following:

execution(modifiers-pattern? ret-type-pattern (@CustomAnnotation declaring-type-pattern?).name-pattern(param-pattern) throws-pattern?)

Having it in the beginning will select any methods with Custom annotation on the method:
execution(@CustomAnnotation modifiers-pattern? ret-type-pattern declaring-type-pattern?.name-pattern(param-pattern) throws-pattern?)

So with this fix the correct pointcut expression becomes, and this selects the methods of Class1:

@Pointcut("execution(* (@CustomAnnotation *).*(..))")
public void methodsInAnnotatedTypes(){
 
}


Saturday, January 19, 2013

Mixin in Java with Aspects - for a Scala traits sample

Scala traits allow new behaviors to be mixed into a class.

Consider two traits to add auditing and version related fields to JPA entities:

package mvcsample.domain

import javax.persistence.Version
import scala.reflect.BeanProperty
import java.util.Date

trait Versionable {
  @Version
  @BeanProperty
  var version: Int = _
}

trait Auditable {
  @BeanProperty
  var createdAt: Date = _
 
  @BeanProperty
  var updatedAt: Date = _
}

Now to mix in 'Versionable' and 'Auditable' with their fields and behavior in a Member entity:

@Entity
@Table(name = "members")
class Member(f: String, l: String) extends BaseDomain with Auditable with Versionable {

  def this() = this(null, null)

  @BeanProperty
  var first: String = f

  @BeanProperty
  var last: String = l

  @OneToMany(fetch = FetchType.EAGER, mappedBy = "member")
  @BeanProperty
  var addresses: java.util.List[Address] = _
}

trait BaseDomain {
  @BeanProperty
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "id")
  @Id
  var id: Long = 0
}


The Member class above will now have the behavior of the BaseDomain class, and will have the behavior of Versionable trait and the Auditable trait.

This kind of mixin is not possible with plain Java, as the equivalent of traits with fields and behavior would be an abstract(or concrete) class and Java allows deriving only from 1 base class. However with AspectJ it is possible to achieve an equivalent of mixin.

Consider the following aspects defined using Aspectj language:
package mvcsample.aspect;

import javax.persistence.Column;
import javax.persistence.Version;
import mvcsample.annot.Versioned;

public interface Versionable {
    
    static aspect VersionableAspect {
        declare parents: @Versioned  mvcsample.domain.* implements Versionable;
        
        @Version
        @Column(name = "version")
        private Integer Versionable.version;    
        
        public Integer Versionable.getVersion() {
        return this.version;
            }
        
        public void Versionable.setVersion(Integer version) { 
        this.version = version;
        }
    }
}


package mvcsample.aspect;

import java.util.Date;
import javax.persistence.Column;

import mvcsample.annot.Audited;
public interface Auditable {
    static aspect AuditableAspect {
        declare parents: @Audited mvcsample.domain.* implements Auditable ;
    
        @Column(name="created_at")
        private Date Auditable.createdAt;
        
        @Column(name="updated_at")
        private Date Auditable.updatedAt;
        
        public Date Auditable.getCreatedAt(){
            return this.createdAt;
        }
        
        public void Auditable.setCreatedAt(Date createdAt) {
            this.createdAt = createdAt;
        }
        
        public Date Auditable.getUpdatedAt(){
            return this.updatedAt;
        }
        
        public void Auditable.setUpdatedAt(Date updatedAt) {
            this.updatedAt = updatedAt;
        }
    }
}

"declare parents: @Versioned mvcsample.domain.* implements Versionable;" aspectj construct adds 'Versionable' interface as a parent to any class in package 'mvcsampple.domain' annotated with @Versioned, similarly the one for 'Auditable'
Then the aspect goes about adding fields to the Versionable interface which in turn ends up adding(mixing in) the fields to the targeted entity classes, this way the Audit related and Version related fields and methods get mixed into the entity classes.

With these two aspects defined, a target entity class would look like this:
@Entity
@Table(name="members")
@Access(AccessType.FIELD)
@Versioned
@Audited
public class Member extends BaseDomain{
 
 public Member(){}
 
 public Member(String first, String last){
  this.first = first;
  this.last = last;
 }
 
 private String first;
 
 @Size(min=1)
 private String last;
 
 @OneToMany(fetch=FetchType.EAGER, mappedBy="member")
 private List<Address> addresses = new ArrayList<>();
 
    ...
}


The fields and behavior defined in the Versionable and Auditable aspects would be mixed into this entity(more generally into any entity with @Versioned and @Audited annotations)

Probably not as clean as Scala traits but works nicely.

Monday, September 3, 2012

Ways to wire dependencies for an object outside of a Spring Container

There are a few interesting ways of setting the properties and dependencies of an object instantiated outside of a Spring container.

Use Cases

To start with, why would we need to do inject in dependencies outside of a Spring container - I am aware of three use cases where I have instantiated objects outside of the Spring container and needed to inject in dependencies.

Consider first the case of a series of tasks executed using a Spring TaskExecutor, the tasks highlighted below are instantiated outside of a Spring container:

List<Callable<ReportPart>> tasks = new ArrayList<Callable<ReportPart>>();
        List<ReportRequestPart> reportRequestParts = reportRequest.getRequestParts();
        for (ReportRequestPart reportRequestPart : reportRequestParts) {
            tasks.add(new ReportPartRequestCallable(reportRequestPart, reportPartGenerator));
        }

        List<Future<ReportPart>> responseForReportPartList;
        List<ReportPart> reportParts = new ArrayList<ReportPart>();
        try {
            responseForReportPartList = executors.invokeAll(tasks);
            for (Future<ReportPart> reportPartFuture : responseForReportPartList) {
                reportParts.add(reportPartFuture.get());
            }

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }

public class ReportPartRequestCallable implements Callable<ReportPart> {
 private final ReportRequestPart reportRequestPart;
 private final ReportPartGenerator reportPartGenerator;

 public ReportPartRequestCallable(ReportRequestPart reportRequestPart, ReportPartGenerator reportPartGenerator) {
     this.reportRequestPart = reportRequestPart;
     this.reportPartGenerator = reportPartGenerator;
    }

 @Override
    public ReportPart call() {
    return this.reportPartGenerator.generateReportPart(reportRequestPart);
    } 
}

The second use case is with ActiveRecord pattern say with the samples that come with Spring Roo, consider the following method where a Pet class needs to persist itself and needs an entity manager to do this:
@Transactional
    public void Pet.persist() {
        if (this.entityManager == null) this.entityManager = entityManager();
        this.entityManager.persist(this);
    }

The third use case is for a tag library which is instantiated by a web container, but needs some dependencies from Spring.


Solutions

1. The first approach is actually simple, to provide the dependencies at the point of object instantiation, through constructors or setters. This is what I have used with the first use case where the task has two dependencies which are being provided by the service instantiating the task:

tasks.add(new ReportPartRequestCallable(reportRequestPart, reportPartGenerator));


2. The second approach is a to create a factory that is aware of the Spring container, declaring the beans that are required with a prototype scope within the container and getting the beans by a getBeans method of the application context,

Declaring the bean as a prototype scoped bean:
    <bean name="reportPartRequestCallable" class="org.bk.sisample.taskexecutor.ReportPartRequestCallable" scope="prototype">
     <property name="reportPartGenerator" ref="reportPartGenerator"></property>
    </bean>
    
    <bean name="reportPartRequestCallableFactory" class="org.bk.sisample.taskexecutor.ReportPartRequestCallableFactory"/>

and the factory serving out the bean:
public class ReportPartRequestCallableFactory implements ApplicationContextAware{
 private ApplicationContext applicationContext;

 @Override
 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  this.applicationContext = applicationContext;
 }
 
 public ReportPartRequestCallable getReportPartRequestCallable(){
  return this.applicationContext.getBean("reportPartRequestCallable", ReportPartRequestCallable.class);
 }
}


3.  The third approach is a variation of the above approach is to instantiate the bean and then inject dependencies using AutoWireCapableBeanFactory.autowireBean(instance), this way:
public class ReportPartRequestCallableFactory implements ApplicationContextAware{
 private GenericApplicationContext applicationContext;

 @Override
 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  this.applicationContext = (GenericApplicationContext)applicationContext;
 }
 
 public ReportPartRequestCallable getReportPartRequestCallable(){
  ReportPartRequestCallable reportPartRequestCallable = new ReportPartRequestCallable();
  applicationContext.getBeanFactory().autowireBean(reportPartRequestCallable);
  return reportPartRequestCallable;
 }
}



4.  The fourth approach is using @Configurable, the catch though is that it requires AspectJ to work. Spring essentially enhances the constructor of the class to inject in the dependencies along the lines of what is being explicitly done in the third approach above:

import org.springframework.beans.factory.annotation.Configurable;

@Configurable("reportPartRequestCallable")
public class ReportPartRequestCallable implements Callable<ReportPart> {
    private ReportRequestPart reportRequestPart;
    @Autowired private ReportPartGenerator reportPartGenerator;

    public ReportPartRequestCallable() {
    }

    @Override
    public ReportPart call() {
       return this.reportPartGenerator.generateReportPart(reportRequestPart);
    }

    public void setReportRequestPart(ReportRequestPart reportRequestPart) {
        this.reportRequestPart = reportRequestPart;
    }

    public void setReportPartGenerator(ReportPartGenerator reportPartGenerator) {
        this.reportPartGenerator = reportPartGenerator;
    }
}

The following is also required to configure the Aspect responsible for @Configurable weaving:
<context:spring-configured/>

With these changes in place, any dependency for a class annotated with @Configurable is handled by Spring even if the construction is done completely outside of the container:

    @Override
    public Report generateReport(ReportRequest reportRequest) {
        List<Callable<ReportPart>> tasks = new ArrayList<Callable<ReportPart>>();
        List<ReportRequestPart> reportRequestParts = reportRequest.getRequestParts();
        for (ReportRequestPart reportRequestPart : reportRequestParts) {
            ReportPartRequestCallable reportPartRequestCallable = new ReportPartRequestCallable(); 
            reportPartRequestCallable.setReportRequestPart(reportRequestPart);
            tasks.add(reportPartRequestCallable);
        }
    .......


Conclusion
All of the above approaches are effective with injecting in dependencies in objects which are instantiated outside of a container. I personally prefer to use Approach 4 (using @Configurable) in cases where AspectJ support is available, else I would go with Approach 2(hiding behind a factory and using a prototype bean).

Saturday, March 10, 2012

Code Policy Enforcement using AspectJ

AspectJ has a feature using which some of the architecture policies can be enforced in the codebase. This is the domain of static code analysis tools like PMD and Checkstyle, however AspectJ also can be a very good fit here, in providing a compile time feedback on any standard violations and if AJDT is integrated with Eclipse in providing an immediate feedback on violations to the developer .

Consider a simple rule that I had for one of my projects. I wanted to prevent @Cachable annotation to be used in the Controllers. A policy aspect enforcing this rule will look like this:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Controller;
public aspect NoCachingInController {
    declare error: execution(@RequestMapping @Cacheable * (@Controller *).*(..)) : "Contoller methods should not have the Cacheable annotation";
}

Now if anybody happens to add @Cacheable to the Controller methods would see the following in the Eclipse IDE with AJDT integrated:


And would see the following at the point of compilation:



Thursday, September 8, 2011

Simple Introduction to AOP - Session 5

This will be a wrap up of the AOP intro, with an example that will comprehensively exercise the concepts introduced in the previous sessions.

The use case is simple, I am going to define a custom annotation, PerfLog, I expect the calls to methods annotated with this annotation to be timed and logged.
Let me start by defining the annotation:

package org.bk.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface PerfLog {
    
}
Now to annotate some service methods with this annotation:

@Service
public class DefaultInventoryService implements InventoryService{
    
    private static Logger logger = LoggerFactory.getLogger(InventoryService.class);

    
    @Override
    public Inventory create(Inventory inventory) {
        logger.info("Create Inventory called");
        inventory.setId(1L);
        return inventory; 
    }

    @Override
    public List<Inventory> list() {
        return new ArrayList<Inventory>();
    }

    @Override
    @PerfLog
    public Inventory update(Inventory inventory) {
        return inventory;
    }

    @Override
    public boolean delete(Long id) {
        logger.info("Delete Inventory called");
        return true;
    }

    @Override
    @PerfLog
    public Inventory findByVin(String vin) {
        logger.info("find by vin called");
        return new Inventory("testmake", "testmodel","testtrim","testvin" );
    }

    @Override
    @PerfLog
    public Inventory compositeUpdateService(String vin, String newMake) {
        logger.info("composite Update Service called");
        Inventory inventory = findByVin(vin);
        inventory.setMake(newMake);
        update(inventory);
        return inventory;
    }
}

Here three methods of DefaultInventoryService have been annotated with @PerfLog annotation - update, findByVin, compositeUpdateService which internally invokes the methods findByVin and update.

Now for the Aspect which will intercept all calls to methods annotated with @PerfLog and log the time taken for the method call:

package org.bk.inventory.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Aspect
public class AuditAspect {

    private static Logger logger = LoggerFactory.getLogger(AuditAspect.class);

    @Pointcut("execution(@org.bk.annotations.PerfLog * *.*(..))")
    public void performanceTargets(){}
   

    @Around("performanceTargets()")
    public Object logPerformanceStats(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);
        }
    }
}

Here the pointcut expression -
@Pointcut("execution(@org.bk.annotations.PerfLog * *.*(..))")
selects all methods annotated with @PerfLog annotation, and the aspect method logPerformanceStats logs the time taken by the method calls.

To test this:
package org.bk.inventory;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;

import org.bk.inventory.service.InventoryService;
import org.bk.inventory.types.Inventory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/testApplicationContextAOP.xml")
public class AuditAspectTest {

    @Autowired 
    InventoryService inventoryService;
        
    @Test
    public void testInventoryService() {
        Inventory inventory = this.inventoryService.create(new Inventory("testmake", "testmodel","testtrim","testvin" ));
        assertThat(inventory.getId(), is(1L));
        
        assertThat(this.inventoryService.delete(1L), is(true));
        assertThat(this.inventoryService.compositeUpdateService("vin","newmake").getMake(),is("newmake"));
    }

}

When this test is invoked the output is the following:
2011-09-08 20:54:03,521 org.bk.inventory.service.InventoryService - Create Inventory called
2011-09-08 20:54:03,536 org.bk.inventory.service.InventoryService - Delete Inventory called
2011-09-08 20:54:03,536 org.bk.inventory.service.InventoryService - composite Update Service called
2011-09-08 20:54:03,536 org.bk.inventory.service.InventoryService - find by vin called
2011-09-08 20:54:03,536 org.bk.inventory.aspect.AuditAspect - Inventory org.bk.inventory.service.DefaultInventoryService.findByVin(String) took 64893 ns
2011-09-08 20:54:03,536 org.bk.inventory.aspect.AuditAspect - Inventory org.bk.inventory.service.DefaultInventoryService.update(Inventory) took 1833 ns
2011-09-08 20:54:03,536 org.bk.inventory.aspect.AuditAspect - Inventory org.bk.inventory.service.DefaultInventoryService.compositeUpdateService(String, String) took 1371171 ns

the advice is correctly invoked for findByVin, update and compositeUpdateService.

This sample is available at : git://github.com/bijukunjummen/AOP-Samples.git


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

Friday, September 2, 2011

Simple Introduction to AOP - Session 4

Yet another way to define an aspect - this time using native aspectj notation.
package org.bk.inventory.aspect;

import org.bk.inventory.types.Inventory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public aspect AuditAspect {
    private static Logger logger = LoggerFactory.getLogger(AuditAspect.class);

    pointcut serviceMethods() : execution(* org.bk.inventory.service.*.*(..));

    pointcut serviceMethodsWithInventoryAsParam(Inventory inventory) : execution(* org.bk.inventory.service.*.*(Inventory)) && args(inventory);

    before() : serviceMethods() {
        logger.info("before method");
    }

    Object around() : serviceMethods() {
        long start = System.nanoTime();
        Object result = proceed();
        long end = System.nanoTime();
        logger.info(String.format("%s took %d ns", thisJoinPointStaticPart.getSignature(),
                (end - start)));
        return result;
    }

    Object around(Inventory inventory) : serviceMethodsWithInventoryAsParam(inventory) {
        Object result = proceed(inventory);
        logger.info(String.format("WITH PARAM: %s", inventory.toString()));
        return result;
    }
    after() : serviceMethods() {
        logger.info("after method");
    }
}


This maps to the previously defined @AspectJ notation

Since this is a DSL specifically for defining Aspects, it is not understood by the java compiler. AspectJ provides a tool(ajc) to compile these native aspectj files and to weave the aspects into the targeted pointcuts. Maven provides a plugin which seamlessly invokes ajc at the point of compilation:

   <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.0</version>
    <dependencies>
     <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>${aspectj.version}</version>
     </dependency>
     <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjtools</artifactId>
      <version>${aspectj.version}</version>
     </dependency>
    </dependencies>
    <executions>
     <execution>
      <goals>
       <goal>compile</goal>
       <goal>test-compile</goal>
      </goals>
     </execution>
    </executions>
    <configuration>
     <outxml>true</outxml>
     <aspectLibraries>
      <aspectLibrary>
       <groupId>org.springframework</groupId>
       <artifactId>spring-aspects</artifactId>
      </aspectLibrary>
     </aspectLibraries>
     <source>1.6</source>
     <target>1.6</target>
    </configuration>
   </plugin>



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

Saturday, August 20, 2011

Simple Introduction to AOP - Session 3

Another way of defining an Aspect is using @AspectJ annotaions - which is natively understood by Spring:
package org.bk.inventory.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Aspect
public class AuditAspect {

    private static Logger logger = LoggerFactory.getLogger(AuditAspect.class);

    @Pointcut("execution(* org.bk.inventory.service.*.*(..))")
    public void serviceMethods(){
        //
    }

    
    @Before("serviceMethods()")
    public void beforeMethod() {
        logger.info("before method");
    }

    @Around("serviceMethods()")
    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);
        }
    }
      
    @After("serviceMethods()")
    public void afterMethod() {
        logger.info("after method");
    }    
}


The @Aspect annotation on the class identifies it as an aspect definition. It starts by defining the pointcuts:
@Pointcut("execution(* org.bk.inventory.service.*.*(..))")
    public void serviceMethods(){}
The above basically identifies all the methods of all types in org.bk.inventory.service package, this pointcut is identified by the name of the method on which the annotation is placed - in this case "serviceMethods". Next, the advice is defined using the @Before(serviceMethods()), @After(serviceMethods()) and @Around(serviceMethods()) annotation and the specifics of what needs to happen is the body of the methods with those annotations. Spring AOP natively understands the @AspectJ annotations, if this Aspect is defined as a bean:
<bean id="auditAspect" class="org.bk.inventory.aspect.AuditAspect" />
Spring would create a dynamic proxy to apply the advice on all the target beans identified as part of the pointcut notation.

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

Saturday, August 13, 2011

Simple Introduction to AOP - Session 2

Here, I will show how the cross-cutting concern that was introduced in the previous session, can be implemented using Spring AOP - Spring offers multiple ways of implementing Aspects - XML configuration based, @AspectJ based. In this specific example, I will use XML configuration file based way of defining the aspect

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 ns
Spring'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

Tuesday, August 9, 2011

A simple introduction to AOP - Session 1

Why use AOP, a simple way to answer this question is to show an implementation of a cross cutting concern without using AOP.

Consider a simple service and it's implementation:
public interface InventoryService {
    public Inventory create(Inventory inventory);
    public List list();
    public Inventory findByVin(String vin);
    public Inventory update(Inventory inventory);
    public boolean delete(Long id);
    public Inventory compositeUpdateService(String vin, String newMake);
}

and its default implementation:
public class DefaultInventoryService implements InventoryService{
    
    @Override
    public Inventory create(Inventory inventory) {
        logger.info("Create Inventory called");
        inventory.setId(1L);
        return inventory; 
    }

    @Override
    public List list() {
        return new ArrayList();
    }

    @Override
    public Inventory update(Inventory inventory) {
        return inventory;
    }

    @Override
    public boolean delete(Long id) {
        logger.info("Delete Inventory called");
        return true;
    }
....

This is just one service. Assume that there are many more services in this project.

So now, if there were a requirement to record the time taken by each of the service methods, the option without AOP would be something along the following lines. Create a decorator for the service:
public class InventoryServiceDecorator implements InventoryService{
    private static Logger logger = LoggerFactory.getLogger(InventoryServiceDecorator.class);
    private InventoryService decorated;

    @Override
    public Inventory create(Inventory inventory) {
        logger.info("before method: create");
        long start = System.nanoTime();
        Inventory inventoryCreated = decorated.create(inventory);
        long end = System.nanoTime();
        logger.info(String.format("%s took %d ns", "create", (end-start)) );
        return inventoryCreated;
    }
This decorator would essentially intercept the call on behalf of the decorated, record the time taken for the method call while delegating the call to the decorated object.

Imagine doing this for all the methods and all the services in the project. This is the scenario that AOP addresses, it provides a way for the cross cutting concerns(Recording time for the service method calls for eg.) to be modularized - to be packaged up separately without polluting the core of the classes.

To end the session, a different way to implement the decorator would be using the dynamic proxy feature of Java:


public class AuditProxy implements java.lang.reflect.InvocationHandler {
    
    private static Logger logger = LoggerFactory.getLogger(AuditProxy.class);
    private Object obj;

    public static Object newInstance(Object obj) {
        return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
                .getClass().getInterfaces(), new AuditProxy(obj));
    }

    private AuditProxy(Object obj) {
        this.obj = obj;
    }

    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
        Object result;
        try {
            logger.info("before method " + m.getName());
            long start = System.nanoTime();
            result = m.invoke(obj, args);
            long end = System.nanoTime();
            logger.info(String.format("%s took %d ns", m.getName(), (end-start)) );
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } catch (Exception e) {
            throw new RuntimeException("unexpected invocation exception: " + e.getMessage());
        } finally {
            logger.info("after method " + m.getName());
        }
        return result;
    }
}

So now, when creating an instance of InventoryService, I would create it through the AuditProxy dynamic proxy:
InventoryService inventoryService = (InventoryService)AuditProxy.newInstance(new DefaultInventoryService());

the overridden invoke method of java.lang.reflect.InvocationHandler would intercept all calls to the InventoryService created in this manner, where the cross cutting concern of auditing the method call time is recorded. This way the cross cutting concern is modularized to one place(AuditProxy), but still needs to be explicitly known by the clients of InventoryService, when instantiating InventoryService.

In the next few sessions, I will demonstrate how this can be more cleanly accomplished using Spring AOP, Spring AOP with @AspectJ, AspectJ, @AspectJ with compile time weaving and finish it off with a comprehensive example.

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