Thursday, September 10, 2009

Spring 3.0 AOP: Cheatsheet

Continuing with insights and tips around Spring 3.0, here is a collection of code samples I've established "so far" with my (rather brief) prototyping using that framework. As with all of my cheatsheets, I'm not presenting these things as any kind of definitive reference; they are only from my own experience, done only in a "sandbox" so far -- we've not yet put these things into production. Your contributions and corrections to this cheatsheet, and any of my other ones, are welcome.


Dependencies

The following libraries are needed:

org.springframework.asm-3.0.0.M3.jar
org.springframework.beans-3.0.0.M3.jar
org.springframework.context-3.0.0.M3.jar
org.springframework.core-3.0.0.M3.jar
org.springframework.expression-3.0.0.M3.jar
org.springframework.aop-3.0.0.M3.jar
antlr-3.0.1.jar commons-logging.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.runtime-1.6.5.RELEASE.jar
com.springsource.org.aspectj.weaver-1.6.5.RELEASE.jar

Concepts

Some key terminology and concepts, pulled from the Spring 3.0 Reference doc - I'll just copy key pieces verbatim first and then paraphrase at the end:
  • 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 Spring AOP, aspects are implemented using regular classes (the schema-based approach) or regular classes annotated with the @Aspect annotation (the @AspectJstyle).
  • 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. Many AOP frameworks, including Spring, model an advice as an interceptor, maintaining a chain of interceptors around the join point.
  • Pointcut: 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.

So an aspect is a class that contains methods referred to as "advice". The advice is executed as specified by the annotation (before, after, etc.) and the "pointcut", or predicate (what classes/methods match the expression). The point in the application where the advice is applied is a "join point". The runtime object containing these join points (i.e., being advised by one or more aspects) is the "target" or "advised object". Spring uses proxying to accomplish the advising (see section 8.6.1 - really, read it, it's short and helpful), and will use JDK dynamic proxies if all advised objects implement at least one interface. Finally, "introductions" are a mechanism where advised objects can be transparently made to implement new interfaces (to retrofit things like caching, comparability, serialization, immutability, etc.), with the advice providing an implementation of the interface, and being handed a reference to the advised object that it can use to invoke the new interface methods.


Problem Space

Recommendations in the following discussions are in bold-face.

The proof-of-concept application is a trivial tongue-in-cheek model of a "family service", where my son Connor and my Siberian Husky Nika would each like to get my attention. It happens. Spring IoC is used to declaratively determine who wins; since that's a static configuration, it's for now the same answer every time.

So the basic idea is a shown in the UML: we have a FamilyService with a FamilyMember property, and two FamilyMembers, each with a name property.

Note that all classes implement an interface. This is in general a good idea for testability, etc. but in particular with Spring AOP, I'd favor this approach because it facilitates use of JDK dynamic proxies instead of CGLIB proxies. Use of CGLIB should consider these things: (1) more library dependencies, (2) final methods cannot participate in AOP, and (3) constructors are called twice due to CGLIB implementation details.

Short of other insights, I would for now recommend implementing at least one interface for any classes that participate in Spring AOP.

A detailed explanation of the above issue around CGLIB vs JDK dynamic proxying, as well as very clear presentation in general around Spring 3.0, can be found in the Spring Reference doc.



Enabling AOP

The injection of the family member getting my attention is done like this:

<bean id="family-service" class="spring.FamilyService">
 <property name="member">
     <ref local="nikadog"></ref>
 </property>
</bean>

This is typical Spring injection; nothing special here. The more interesting stuff is to now add some AOP. Do this by adding an "aop" namespace to the beans declaration tag and enabling what I would recommend as the preferred flavor of Spring AOP (AspectJ-style annotations plus Spring auto-proxying):
 
 <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/beans
       http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
 ....
   <aop:aspectj-autoproxy/>
 </beans>

The Spring reference doc again provides a clear, useful discussion around the various "flavors" you can use with Spring AOP. Given the tradeoffs described there, I recommend the AspectJ-style annotations with Spring auto-proxying for the following reasons:
  1. Their advice to "use the simplest thing that works" is IMO sound guidance
  2. So, for now, assume that AspectJ-annotations will suffice until you find otherwise
  3. If you need to gain more power, you can migrate easily from the AspectJ-annotations to full-blown AspectJ itself

The limitations to be aware of include these:

  1. AOP can only be applied to Spring-managed beans (therefore, Spring-declare any classes that will leverage AOP)
  2. AOP mechanisms can be applied only to public method-level executions (excluding constructors)
  3. Methods in AOP-enabled classes that have aspects declared will not see those aspects applied if invoked by other
    methods in that same class (i.e., do not use self-invocation within AOP-enabled classes)

Limitations #2 and #3 are a result of Spring's proxy approach to AOP. See section 8.6.1 in the reference doc for a detailed discussion. Note that a workaround for #3 is discussed in that section, but it involves a tight coupling to Spring and makes the application class acutely aware that it is being AOP-managed, neither of which is a recommended practice.


Simple AOP

To create an aspect with some advice that executes before all public methods in the spring package (see reference doc, section 8.2.3.4 for examples around expression syntax):

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
@Aspect
public class MyAspect {
 /**
  * Log a message before entry to specified methods
  */
  @Before("execution(* spring..*(..))")
  private void logOnEntry(JoinPoint jp) {
     // JoinPoint argument is optional, but recommended as quite useful
     System.out.println("Before " + getSimpleName(jp));
  }
 /**
  * Returns the simple name of the class being advised, as per the given
  * join point.
  */
  private String getSimpleName(JoinPoint jp) {
     return jp.getTarget().getClass().getSimpleName();
  }
 }

The aspect must be managed by Spring to be put into play - add this entry to the configuration file:

<bean id="myAspect" class="spring.MyAspect"> </bean>

As you can see, you can also access the target object via the JoinPoint argument. As such, you can cast it to your application type and execute its public methods.

You can also execute advice after a method or around a method. The @After is analogous to the above example. The "execution" part of the expression is the "pointcut designator" or PCD; there are several others, but "execution" is probably what will be used the most. Since it's indicating a method-level execution, you can alter the method-portion of the expression to e.g. address only setters:

@Before("execution(* spring..set*(..))")

To address executions at a type level (i.e. all public methods in a given type), use the "within" PCD:

@After("within(*.*Service)")

You can also use the Spring bean ID declaration as an alias for a given type; so, given this bean declaration:

<bean id="family-service" class="spring.FamilyService"></bean>

...you can specify this join point using the "bean" PCD:

@After("bean(family-service)")


Reusable Pointcuts

Reusable pointcuts can be established:

/**
 * Establish a pointcut on execution of any and all public methods
 */
@Pointcut("execution(* *.*(..))")
public void anyMethod() {}

Pointcuts can be combined to form conditional expressions, using AND, OR and NOT operators (&&, ||, and !):

@Pointcut("within(com.xyz.service..*)")
private void inServiceModule() {}
@Pointcut("anyMethod() && inServiceModule()")
private void serviceOperation() {}

To intercept the throwing of an exception resulting in a method exit, using the "anyMethod" pointcut established above:

/**
 * Intercept execution when any method exits by throwing any exception
 */
 @AfterThrowing(pointcut = "anyMethod()", throwing = "ex")
 private void trackExceptions(JoinPoint jp, Exception ex) {
     System.out.println("Exception thrown from "           + getSimpleName(jp) + ": " + ex);
 }

To intercept the value returned from a specified pointcut:

 /**
  * Establish a pointcut on execution of specified method
  */
  @Pointcut("execution(* spring.Nika.getName())")
  public void getNikadogName() {}
 /**
  * Intercept the return from specified pointcut
  */
  @AfterReturning(pointcut = "getNikadogName()", returning = "name")
  private void getNikaName(String name) {
      System.out.println("after returning from nikadog, pointcut name: "
           + name + "...");
  }


Beyond the Simple

The @Around PCD is bit more sophisticated:

 /**
  * Establish a pointcut on execution of specified method
  */
  @Pointcut("execution(* FamilyService.getMember(..))")
  public void getMember() {}
 /**
  * Wrap specified method to get profiling information. Can also use this pattern
  * for tracing, caching, etc.
  */
  @Around("getMember()")
  private FamilyMember doProfiling(ProceedingJoinPoint pjp)  throws Throwable {
    long start = System.currentTimeMillis();
    FamilyMember member = (FamilyMember) pjp.proceed();
    System.out.println("Elapsed time to get member: " +        (System.currentTimeMillis() - start));
     return member;
 }

In the above snippet, the ProceedingJoinPoint facilitates setting things up before the advised object method is executed (i.e. start the stopwatch, check the cache for a hit, etc.), then supports (optionally!) executing the method, and finally returning the appropriate value - so you can see that this decorates the object execution with your own proxying code. Note that you can easily check a cache for a "hit", then simply return the cached value if it's there without executing the method, otherwise executing the method and stuffing it in the cache for subsequent requests. Using the "args" PCD, you can (e.g.) examine incoming argument values to qualify what specific object in the cache is being requested.

Note that this approach to caching relies on the aspect to manage the cache. An alternate approach will be presented in the "Introductions" section below.

Suppose our service class was throwing an exception, and we want to apply a retry strategy since the problem involves waiting for some remote resource to become available (e.g. the database is spinning up):

@Around("getMember()")
 private FamilyMember retry(ProceedingJoinPoint pjp) throws Throwable {
     int numAttempts = 0;
     int maxRetries = 5;
     Throwable t = null;
     do {
        numAttempts++;
        try {
            return (FamilyMember)pjp.proceed();
        } catch (DatabaseNotReadyException ex) {
            System.out.println("=========== Caught exception from "
                 + getSimpleName(pjp)
                + "; retry attempt #" + numAttempts + "==============");
            t = ex;
        }
     } while (numAttempts <= maxRetries);
              throw t;
   }

Introductions

A technique described above for caching relies on the aspect itself to manage the cache. An alternate approach is to implement an interface that prescribes caching functionality:

public interface Cacheable {
     public boolean isCached();
     public void save(Object obj);
     public Object fetch();
}
But we may be motivated to regard this cacheability as a cross-cutting concern, one that should be maintained and managed (enable/disable, track hits, monitor throughput gains, flush the cache, etc.) separately from the pure business logic (vs simply having FamilyService implement the interface explicitly, i.e. such that one's business classes are not responsible for determining their own "cacheability" - that's an orthogonal concern). If so, we can use AOP "introductions" to retrofit the caching.

An implementation supporting the FamilyService (and, for that matter, other services in general) might begin life like this:

public class CacheableImpl implements Cacheable {
      private boolean cached = false;
      private Object cachedObject = null;
      public boolean isCached() {
        return cached;
     }
      public void save(Object obj) {
        cachedObject = obj;
        cached = true;
     }
      public Object fetch() {
        return cachedObject;
     }
}
An "introduction" is a way of retrofitting an implementation of an interface onto the target object. Since it's AOP, the target object does not and need not know it's being decorated like this. The somewhat cryptic syntax to make it happen is encapsulated in the aspect:
@DeclareParents(value = "spring.FamilyService", defaultImpl = CacheableImpl.class)
 public static Cacheable mixin;
 .......
 @Around("getMember() && this(service)")
 public FamilyMember checkCache(ProceedingJoinPoint jp, Cacheable service) throws Throwable {
     if (service.isCached())  {
        System.out.println(" ---> Returning cached member");
        return (FamilyMember) service.fetch();
     }
     System.out.println(" ---> Member NOT cached; call service and save result...");
     FamilyMember member = (FamilyMember) jp.proceed();
     service.save(member);
     return member;
 }
Now, instead of relying on the aspect to manage caching - arguably a questionable responsibility - the details of caching are factored out to give us better cohesion. This is just one possible use of the AOP introduction.
Resources Spring 3.0.M3 Reference Documentation, by Rod Johnson et. al., 2009 Spring Framework

Wednesday, September 9, 2009

Spring Test Framework Cheatsheet

This documents some prototyping done with the Spring Test Framework (I'll refer to this as the STF). Effectively it is a paraphrase/summary of what's written up in the Chapter 10 of the Spring Framework Reference document, version 3.0.M3, with some example code snippets that I was able to get working. Consult that writeup for further detail.

Here are the high-level features of the STF that I'd consider most interesting:
  1. How to fetch the Spring application context object regardless of environment (web container, test environment, etc.)
  2. How to configure test-specific Spring contexts
  3. Simplified access to context beans
  4. Automatic rollback of test case transactions
  5. Auto-rollback without extending a superclass
  6. Odds-n-ends

How to fetch the Spring application context

This first tip is not directly related to the STF, but was discovered during my experiments with it, so I make note of it here.

 In a previous post, I presented a pattern for determining at runtime how to get a reference to the application context that would first look for a web context, and if that failed simply produce a classpath-based context. This pattern requires explicit knowledge not only of what environment is in play, but also knowledge of exactly what Spring context is appropriate for that environment. A simpler pattern can be used as follows - first, provide a class that implements ApplicationAwareContext:


public class ApplicationContextProvider 
    implements ApplicationContextAware { 
    private static ApplicationContext context;
    public static ApplicationContext getApplicationContext() {
        return context;
    }
    public void setApplicationContext(ApplicationContext context) {
        this.context = context;
    }
}

Declare that class as managed by Spring in the context file:

<bean id="appCtxProvider" 
    class="com.twc.registry.common.ApplicationContextProvider">
</bean>

Now, any class that wants a reference to the context instance can do so at runtime, whether in a web or a test/standalone environment:

ApplicationContext context = 
    ApplicationContextProvider.getApplicationContext();
MyBean myBean = (MyBean)context.getBean("my-bean");

That code snippet can of course be encapsulated and parameterized as needed, to facilitate keeping third-party framework specifics in a single point of change.

This precludes the need for a ServletContextListener as described in my previous post, simplifies the mechanics around fetching beans in the context, and eliminates the need for application awareness of explicit subclasses of the Spring ApplicationContext.

In what follows, I'll present an even simpler method for injecting dependencies directly into test classes, such that a reference to the application context is not needed.


How to configure test-specific Spring contexts

If you need to specify certain test fixtures or other test-specific dependencies, it'd be useful to both have these injected (to facilitate reuse and simplify test setup) but keep the configuration for this injection separate from production classes. Using the STF, a convenience idiom supports doing this.

First, to use the STF, add org.springframework.test-3.0.0.M3.jar to your classpath.

Configure a test-specific Spring context using the following annotation:

package com.mybiz;
@ContextConfiguration
public class MyTest {
   @Test
    public void testThis() {
          ApplicationContext ctx = 
              ApplicationContextProvider.getApplicationContext();
          MyBean myBean = (MyBean ) context.getBean("my-bean");
          // now do some tests with myBean...
    }
}

This presumes the existence of a Spring configuration file named com/mybiz/MyTest-context.xml. To otherwise specify the location:

@ContextConfiguration("/WEB-INF/MyTestConfig.xml")

Multiple resources can be specified using comma-separated lists. The default is for subclasses to inherit superclass' resource lists and optionally override bean entries; this inheritance behavior can also be disabled.


Simplified access to context beans

Now, instead of using the ApplicationContextProvider manually as in the above snippet, we can simply do this:

@Autowired  // or can annotate a setter instead of a field
private MyBean myBean;

If there are  multiple MyBean's defined in the Spring context, this type-based wiring will not suffice (without further qualification, which we ignore for now). Instead use injection by name:

@Resource
private MyBean myBean;

However, it appears (empirically...) that @Resource also wires by type, since in the above working example, I hadn't configured a bean with an ID of "myBean". It also "just works" this way:

private MyBean myBean;
@Resource  // also works with @Autowired!
private void setTheBean(MyBean theBean) {  
// notice the field and/or method are both private - but injection still works!
    myBean = theBean;
}


Automatic rollback of test case transactions

By far the most valuable feature of the STF is the ability to execute integration tests against a database without changing the database state - i.e., all transactions are automatically rolled back. Making this work is reasonably simple - first, we'll need Spring context entries to specify a data source and a transaction manager:

<bean id="dbcp-dataSource" 
    class="org.apache.commons.dbcp.BasicDataSource" 
    destroy-method="close">
    <property name="driverClassName" value="${database.driver}"/>
    <property name="url" value="${database.url}"/>
    <property name="username" value="${database.user}"/>
    <property name="password" value="${database.password}"/>
</bean>
<bean id="txnMgr" 
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dbcp-dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="txnMgr"/>
<aop:aspectj-autoproxy/>

This context configuration file must be loaded using @ContextConfiguration; we must declare @Transactional either at the class or method level; and since our transaction manager is not named "transactionManager" (the default) -- or if we would ever wish to disable auto-rollback at the class level -- we'll need to add a @TransactionConfiguration annotation:

@ContextConfiguration(locations = {"/WEB-INF/MyTestConfig.xml"})
@Transactional
@TransactionConfiguration(transactionManager="txnMgr", defaultRollback=true)
public class MyDaoTest extends AbstractTransactionalTestNGSpringContextTests {
.......
// override auto-rollback on per-method basis
    @Test
    @Rollback(false)
    public void keepThisTransactionInPlace() {
        ......
    }
    @BeforeTransaction  
// likewise, @AfterTransaction follows the transaction
    public void doBeforeTxn()
    {
// do whatever setup needed, if any, before the transaction executes
    }
}

To gain numerous conveniences, we've extended a Spring class specific to the TestNG framework (also available are Junit-specific superclasses). We could have instead added a handful of cruft to get around doing this extension, if e.g. you need to extend your own test superclass or for some other reason you're adverse to this. But the added cruft is so noisy that you'll be motivated to simply encapsulate it in your own superclass anyway, or if that's not feasible then reuse becomes a copy-paste headache. If possible, simply extending the Spring-provided convenience classes is probably the simplest thing to do.


Auto-rollback without extending a superclass

But if you must know, here's the cruft you'll need to avoid extending AbstractTransactionalTestNGSpringContextTests:

@ContextConfiguration(locations = {"/WEB-INF/MyTestConfig.xml"})
@TestExecutionListeners({DependencyInjectionTestExecutionListener.class, 
    DirtiesContextTestExecutionListener.class,
    TransactionalTestExecutionListener.class})
@Transactional
@TransactionConfiguration(transactionManager="txnMgr")
public class MyDaoTest implements IHookable, ApplicationContextAware {
    private ApplicationContext applicationContext;
    private final TestContextManager testContextManager;
    private Throwable testException;
    public MyDaoTest() {
        this.testContextManager = new TestContextManager(getClass());
    }
    public final void setApplicationContext(
        ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
    @BeforeClass(alwaysRun = true)
    protected void springTestContextPrepareTestInstance() 
    throws Exception {
        this.testContextManager.prepareTestInstance(this);
    }
    @BeforeMethod(alwaysRun = true)
    protected void springTestContextBeforeTestMethod(Method testMethod) 
    throws Exception {
        this.testContextManager.beforeTestMethod(this, testMethod);
    }
    public void run(IHookCallBack callBack, ITestResult testResult) {
        callBack.runTestMethod(testResult);
        this.testException = testResult.getThrowable();
    }

    @AfterMethod(alwaysRun = true)
    protected void springTestContextAfterTestMethod(Method testMethod) 
    throws Exception {
        try {
            this.testContextManager.afterTestMethod(
                this, testMethod, this.testException);
        }
        finally {
            this.testException = null;
        }
    }

Ugly, ugly, ugly. Encapsulate!


Odds-n-Ends

There are numerous other facilities in the STF; consult Chapter 10 for the full discussion. Worth mentioning here are the following:
  1. automatic caching of loaded application contexts, to save startup time on per-method basis, once for each test fixture. Optionally instruct the framework to reload the context in case changes to state of beans in that context that are not meant to be preserved across all tests in a given fixture.
  2. JDBC utility class to facilitate querying database state.
  3. Mock objects ready-to-go for JNDI and Servlet API.
Overall, two thumbs up: this is definitely a new item in my toolbox.