ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

An Introduction to Aspect-Oriented Programming with the Spring Framework, Part 2
Pages: 1, 2

Using Spring AOP to Implement the Cuckoo's Egg Design Pattern

Aspect-oriented programming is still a fairly young discipline, especially when compared to its evolutionary parent: object-oriented programming. Design patterns are usually understood to be generic solutions to common problems and, as AO is so young, there are relatively few aspect-oriented design patterns yet discovered.



One pattern of usage that is starting to emerge I am calling here the Cuckoo's Egg design pattern. This pattern has other aliases and object-oriented peers including Mock Object and Mock Testing; even the Proxy pattern has certain similarities.

The Cuckoo's Egg aspect-oriented design pattern can be defined as the transparent and modular replacement of a feature within an application's context. Much as a cuckoo deposits its own egg into another bird's nest surreptitiously, the Cuckoo's Egg design pattern deposits a replacement feature implementation in place of an existing feature, causing as little disturbance as possible.

This replacement can be implemented statically, dynamically, partially, fully, across parts of an object, or across component boundaries. Using AO the feature replacement is achieved transparently without the need for any changes throughout the rest of the application. The replacement feature, which is to take the place of an existing feature within the application, fulfills the cuckoo's-egg role. Figure 6 shows the main components of the Cuckoo's Egg design pattern.

Figure 6
Figure 6. The main roles in the Cuckoo's Egg design pattern

The Cuckoo's Egg design pattern relies on the concept of around advice. You need to have the power of the active and intrusive around advice in order to intercept and effectively replace an existing feature within an application.

For more information on the Cuckoo's Egg design pattern, and an alternative implementation in AspectJ, see the AspectJ Cookbook (O'Reilly), due for release in December 2004.

To implement the Cuckoo's Egg design pattern using Spring AOP, you need to declare an around advice that intercepts all of the calls to the feature that is to be replaced. Unlike hot-swappable target sources, a feature of Spring AOP that will be covered in another article in this series, the explicit use of around advice allows your Cuckoo's Egg implementation to effectively cross object boundaries (and therefore bean boundaries) to deal with an entire feature's replacement, as shown in Figure 7.

Figure 7
Figure 7. A component crossing bean boundaries

The following code shows a simple application with two beans where a feature spans multiple areas of the application. The feature to be replaced can be thought of as encompassing the foo() method on the IBusinessLogic bean and the bar() method on the IBusinessLogic2 bean. The baz() method on the IBusinessLogic2 bean is not part of the feature and so is not included in the replacement.

public interface IBusinessLogic
{
   public void foo();
}

public interface IBusinessLogic2
{
   public void bar();
   
   public void baz();
}

The full source code for this example is available for download in the Resources section at the end of this article.

The ReplacementFeature class takes the role of the cuckoo's egg by providing the replacement implementation that is to be transparently introduced into your application. The ReplacementFeature class implements all of the methods that are to be replaced through its introduction.

public class ReplacementFeature
{
   public void foo()
   {
      System.out.println(
         "Inside ReplacementFeature.foo()");
   }
   
   public void bar()
   {
      System.out.println(
         "Inside ReplacementFeature.bar()");
   }
}

You now need to declare some around advice to intercept calls to the cross-bean feature's methods. The CuckoosEgg class provides some around advice that examines the method that has been intercepted and then passes the appropriate method call to the instance of the ReplacementFeature class.

public class CuckoosEgg implements MethodInterceptor
{
   public ReplacementFeature replacementFeature =
       new ReplacementFeature();
   
   public Object invoke(MethodInvocation invocation)
       throws Throwable
   {
      if (invocation.getMethod().getName().equals("foo"))
      {
         replacementFeature.foo();
      }
      else
      {
         replacementFeature.bar();
      }
      
      return null;
   }
}

The details of the Cuckoo's Egg design, as with so much in the Spring framework, is in the springconfig.xml configuration file. The changes to the springconfig.xml file simply ensure that any calls made to the foo() and bar() methods on the IBusinessLogic and IBusinessLogic2 beans are intercepted and channeled to the CuckoosEgg class's around advice.

   ...
   
   <!--CONFIG-->
   <bean id="businesslogicbean" 
      class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
         <value>IBusinessLogic</value>
      </property>
      <property name="target">
         <ref local="beanTarget"/>
      </property>
      <property name="interceptorNames">
         <list>
            <value>theCuckoosEggAdvisor</value>
         </list>
      </property>
   </bean>
   
   <bean id="businesslogicbean2" 
      class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
         <value>IBusinessLogic2</value>
      </property>
      <property name="target">
         <ref local="beanTarget2"/>
      </property>
      <property name="interceptorNames">
         <list>
            <value>theCuckoosEgg2Advisor</value>
         </list>
      </property>
   </bean>

   <!--CLASS-->
   <bean id="beanTarget" class="BusinessLogic"/>
   <bean id="beanTarget2" class="BusinessLogic2"/>
   
   <!--ADVISOR-->
   <bean id="theCuckoosEggAdvisor" 
      class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      <property name="advice">
         <ref local="theReplacementFeaturePart1Advice"/>
      </property>
      <property name="pattern">
         <value>IBusinessLogic.*</value>
      </property>
   </bean>
   
   <bean id="theCuckoosEgg2Advisor" 
      class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      <property name="advice">
         <ref local="theReplacementFeaturePart2Advice"/>
      </property>
      <property name="pattern">
         <value>IBusinessLogic2.bar*</value>
      </property>
   </bean>
   
   <!--ADVICE-->
   <bean id="theReplacementFeaturePart1Advice" class="CuckoosEgg"/>
   <bean id="theReplacementFeaturePart2Advice" class="CuckoosEgg"/>
   
   ...

When the example application is run using the amended springconfig.xml, the method calls designated as part of the feature to be replaced are properly intercepted and passed to the ReplacementFeature class.

You can always implement a design pattern in different ways, even within the same implementation environment. Another way of implementing the example shown above would be to implement two separate pieces of advice.

Finally, you need to take care that the lifecycle of the feature that you are replacing using the Cuckoo's Egg design pattern, be it cross-bean or within one class, matches the object lifecycle of the feature it is replacing. In the example above there is no problem, as there is only one instance of the feature being replaced, and the singleton Cuckoo's Egg advice maintains only one replacement feature.

This is a very simple example and it is likely that you will have to deal with a number of feature instances that need to be replaced by separate Cuckoo's Egg instances. In this case, an individual aspect instance needs to be tied to an individual instance of the feature being replaced. The next article in this series will attack this problem when it considers the use of aspect lifecycles.

Conclusion

This article has shown how to carefully use the active around form of advice inside of the Spring framework. The around form of advice is commonly used when implementing the Cuckoo's Egg design pattern, and so you were shown one example of how this aspect-oriented design pattern can be implemented using Spring AOP.

In the third article in this series, you will be shown how to use more of the fundamental AOP concepts available in the Spring framework. These concepts will include controlling aspect lifecycles, affecting the static structure of your application using active aspects based on introduction advice, and gaining even finer control over your aspect weaving using the control flow pointcut.

Resources

Russell Miles is a senior consultant for SpringSource in the UK and contributes to various open source projects while working on books for O'Reilly.


Return to ONJava.com.