Spring AOP - HelloWorld
- JavaTouch   - Spring Framework   - AOP

-Introduction to Spring Framework with "Hello World"

We will start our application using code from our Introduction to Spring Framework with "Hello World". There we have IGreetingService interface, its implementation class GreetingServiceImpl and our Spring configuration file is hello.xml. Our main application class is HelloApp. Our simple starting application code is as follows.

IGreetingService.java

package com.javaTouch.hello;
public interface IGreetingService

  public void sayGreeting();
}

 

GreetingServiceImpl.java

package com.javaTouch.hello;
public class GreetingServiceImpl implements IGreetingService {
  public void sayGreeting() {
    System.out.println("Hello World");
  }
}
 

 

hello.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

       "
http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="greetingService"
          class="com.javaTouch.hello.GreetingServiceImpl">
   
</bean>
</beans>

 

HelloApp.java

package com.javaTouch.hello;
import com.javaTouch.hello.IGreetingService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class HelloApp {
   public static void main(String[] args) throws Exception {  
      // Read the configuration file
      ApplicationContext ctx
          = new FileSystemXmlApplicationContext("hello.xml");

      //Instantiate an object
      IGreetingService greetingService = (IGreetingService) ctx.getBean("greetingService");

      //Execute the public method (the test)
      greetingService.sayGreeting();
   }
}

There's nothing too worrying in the GreetingServiceImpl class or its associated interface. However, the HelloApp class does something interesting in how it initializes the GreetingServiceImpl object. By using the ctx.getBean("greetingService") call, the HelloApp hands off the loading and management of bean instance of the BusinessLogic class to the Spring framework.

Allowing Spring to control the initialization of the BusinessLogic bean gives the Spring runtime the opportunity to do all of the management tasks required of a J2EE system for the bean before it is handed back to the application. The configuration of the Spring runtime can then decide which tasks and modules are to be applied to the bean. This configuration information is provided by an XML file similar to the one shown below.

This configuration file, saved as hello.xml, specifies that a bean is to be loaded whose interface matches IGreetingService. The bean is then tied to the implementation class GreetingServiceImpl. This may seem like a lot of effort just to get a simple bean loaded and to call a single method, but remember that this configuration file is an integral piece of the puzzle that enables the Spring framework to transparently apply its components to your application.

Now lets have a look at slightly different version of Spring configuration file hello.xml and our application java class HelloApp.java as given below.

hello.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

       "
http://www.springframework.org/dtd/spring-beans.dtd">

   <!-- Bean configuration -->
   <bean id="greetingBean"
   class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
         <value>com.javaTouch.hello.IGreetingService</value>
      </property>
      <property name="target">
         <ref local="greetingService"/>
      </property>
   </bean>

   <!--  Bean Class -->
   <beans>
    <bean id="greetingService"
          class="com.javaTouch.hello.GreetingServiceImpl">
   
</bean>
</beans>

 

Note that in Spring configuration file we have introduced an additional bean named greetingBean which is going to be act as a proxy and it will be targetd to our greetingService bean. Now you may try running our slightly modified application HelloApp class with the new version of Spring Configuration file.

Note that now we get a greetingBean instance and not a greetingService instance as before.

HelloApp.java

package com.javaTouch.hello;
public class
HelloApp {
   public static void main(String[] args) throws Exception {  
      // Read the configuration file
      ApplicationContext ctx
          = new FileSystemXmlApplicationContext("hello.xml");

      // Instantiate an object
      IGreetingService greetingService = (IGreetingService) ctx.getBean("greetingBean");

      //Execute the public method (the test)
      greetingService.sayGreeting();
   }
}

 When you run the modified version of HelloApp class with new hello.xml file. It will not behave differently yet though and result will be good old same "Hello World" message. That is because still we have not added any Aspects. 



"The only source of knowledge is experience."

"The only reason for time is so that everything doesn't happen at once."

"When the solution is simple, God is answering."

"Logic will get you from A to B. Imagination will take you everywhere"

- Albert Einstein

 

Applying a Method Tracing Aspect

Possibly the most basic stalwart of aspects is the Method Tracing aspect. This passive aspect is about as simple an aspect as you will find, and so is the best place to start when investigating a new implementation of AOP.

A Method Tracing aspect captures calls to, and returns from, methods being traced within a target application and displays this information in some way. In AOP, the before and after types of advice are used to capture these types of join points as they can be triggered before and after a method call join point. Using the Spring framework, the before advice for the Method Tracing aspect is declared in the TracingBeforeAdvice class.

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"

       "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
   <!-- Bean configuration -->
   <bean id="greetingBean"
    class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
         <value>com.javaTouch.hello.IGreetingService</value>
      </property>
      <property name="target">
         <ref local="greetingService"/>
      </property>
      <property name="interceptorNames">
        <list>
          <value>theBeforeGreetingAdvisor</value>
        </list>
      </property>
   </bean>

   <!--  Bean Class -->
   <bean id="greetingService"
          class="com.javaTouch.hello.GreetingServiceImpl">
   </bean>
   
   <!-- Advisor pointcut definition for before advice --> 
   <bean id="theBeforeGreetingAdvisor"  
     class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      <property name="advice">
         <ref local="theBeforeGreetingAdvice"/>
      </property>
      <property name="pattern">
         <value>.*</value>
      </property>
   </bean>

   <!-- Advice classes -->
   <bean id="theBeforeGreetingAdvice"
      class="com.javaTouch.hello.BeforeGreetingAdvice"/>   
</beans>

The theBeforeGreetingAdvisor is added to the previously declared greetingBean. The advisor potentially intercepts all join points on the beans to which it is attached. The advisors are beans themselves, and their sole job is to tie together pointcut definitions and advice beans. The pointcut definition in this example is a regular expression specifying the join points of interest within the static object hierarchy.

Since the org.springframework.aop.support.RegexpMethodPointcutAdvisor pointcut advisor is being used in this example, the pointcut logic is specified using a regular expression. The regular expression is used to identify the join points on the public interface to the IGreetingService interface. Some simple examples of regular expressions that could have been used to specify different collections of join points on the IGreetingService interface are:

  • <value>.*</value>: This expression selects all join points on the bean or beans to which the advisor has been attached.
  • <value>./IGreetingService/.sayGreeting</value>: This expression selects join points on the foo() method on the IBusinessLogic interface only. This will only select join points on the IBusinessLogic interface if it is one of the beans to which the advisor has been attached.

The final bean declarations in the springconfig.xml file specify the classes that implement the advice beans.

package com.javaTouch.hello;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

public class BeforeGreetingAdvice implements MethodBeforeAdvice {

  public void before(Method m, Object[] args, Object target) 
                                          throws  Throwable {
    System.out.println("Before calling method: "+ m.getName()
                    + " (by " +  this.getClass().getName() + ")");
 }

}

OutPut:

Before calling method: sayGreeting (by com.javaTouch.hello.BeforeGreetingAdvice)
Hello World

Source Code:
The Source code for the above described "HelloWorld' example can be downloaded from here...

 

References:

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