Enterprise Java

Aspect Oriented Programming with Spring AspectJ and Maven

Spring framework comes with AOP support. In fact, as stated in Spring reference documentation,

One of the key components of Spring is the AOP framework. While the Spring IoC container does not depend on AOP, meaning you do not need to use AOP if you don’t want to, AOP complements Spring IoC to provide a very capable middleware solution. AOP is used in the Spring Framework to…

  • … provide declarative enterprise services, especially as a replacement for EJB declarative services. The most important such service is declarative transaction management. 
  • … allow users to implement custom aspects, complementing their use of OOP with AOP.

Nevertheless Spring AOP framework comes with certain limitations in comparison to a complete AOP implementation, such as AspectJ. The most common problems people encounter while working with Spring AOP framework derive from the fact that Spring AOP is “proxy – based”. In other words when a bean is used as a dependency and its method(s) should be advised by particular aspect(s) the IoC container injects an “aspect – aware” bean proxy instead of the bean itself. Method invocations are performed against the proxy bean instance, transparently to the user, in order for aspect logic to be executed before and/or after delegating the call to the actual “proxy–ed” bean.

Furthermore Spring AOP framework uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. The first one can create proxies only for the interfaces whilst the second is able to proxy concrete classes but with certain limitations. In particular, as stated in Spring reference documentation,

If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used. All of the interfaces implemented by the target type will be proxied. If the target object does not implement any interfaces then a CGLIB proxy will be created.

To summarize, when working with Spring AOP framework you should have two important things in mind :

  1. If your “proxy–ed” bean implements at least one interface, the proxy bean can ONLY be casted to that interface(s). If you try to cast it to the “proxy–ed” bean class, then you should expect a ClassCastException to be thrown at runtime. Nevertheless Spring AOP framework provides the option to force CGLIB proxying but with the aforementioned limitations (please refer to the relevant chapter of Spring reference documentation)
  2. Aspects do not apply to intra–operation calls. Meaning that there is no way for the proxy to intercept the calling of a method originated from another method of the same “proxy–ed” bean

Our recommendation of overcoming the above issues is to use AspectJ weaving. In other words to inject aspect logic directly to the target class and remove the necessity to have all methods being proxied. There are three ways to inject instructions implied by AspectJ aspects :

  1. compile time weaving – compile either target source or aspect classes via the AspectJ compiler
  2. post compile weaving – inject aspect instructions to already compiled classes
  3. load time weaving – inject aspect instructions to the byte code during class loading

It’s possible to use any of the approaches mentioned above. In this tutorial we will present how to use AspectJ compile time weaving with Spring and Maven. We are going to implement a minimal “greeting” Spring service and a relevant “greeting” AspectJ aspect. Spring service method calls will be intercepted by the AspectJ aspect. The AspectJ aspect will enrich Spring service “greeting” message with its own “greeting” message. The “greeting” message of the AspectJ aspect will be injected from the Spring container, just to show how you can inject Spring dependences to AspectJ aspects.

Spring users who have already implemented aspects for their bean services can switch to AspectJ transparently, meaning that no special code needs to be written since Spring AOP framework uses a subset of AspectJ pointcut expression language, and @AspectJ Spring aspects are fully eligible for AspectJ weaving.

Our preferred development environment is Eclipse, so as a prerequisite you must have Eclipse with Maven support installed. The installation of Maven plugin for Eclipse is out of the scope of this tutorial and will not be discussed. Nevertheless you will need the following components :

  1. Eclipse from here
  2. Maven Plugin for Eclipse from here

We will be using Eclipse Galileo, „m2eclipse“ Maven Integration for Eclipse Plugin version 0.10.0, Spring version 3.0.1, aspectjrt version 1.6.7 and aspectj-maven-plugin version 1.3 for this tutorial.

Lets begin,

  1. Create a new Maven project, go to File ? Project ? Maven ? Maven Project
  2. In the „Select project name and location“ page of the wizard, make sure that „Create a simple project (skip archetype selection)“ option is unchecked, hit „Next“ to continue with default values
  3. In the „Select an Archetype“ page of the wizard, select „Nexus Indexer“ at the „Catalog“ drop down list and after the archetypes selection area is refreshed, select the „webapp-jee5“ archetype from „org.codehaus.mojo.archetypes“ to use. You can use the „filter“ text box to narrow search results. Hit „Next“ to continue
  4. In the „Enter an artifact id“ page of the wizard, you can define the name and main package of your project. We will set the „Group Id“ variable to „com.javacodegeeks“ and the „Artifact Id“ variable to „aspectjspring“. The aforementioned selections compose the main project package as „com.javacodegeeks.aspectjspring “ and the project name as „aspectjspring“. Hit „Finish“ to exit the wizard and to create your project

Let’s recap a few things about the Maven Web project structure

  1. /src/main/java folder contains source files for the dynamic content of the application
  2. /src/test/java folder contains all source files for unit tests
  3. /src/main/webapp folder contains essential files for creating a valid web application, e.g. „web.xml“
  4. /target folder contains the compiled and packaged deliverables
  5. The „pom.xml“ is the project object model (POM) file. The single file that contains all project related configuration.

In order to properly use Spring at runtime, we must provide all necessary libraries to the web application. Open the graphical editor of your „pom.xml“ and perform the following changes :

  1. Locate the „Properties“ section at the „Overview“ page of the POM editor and perform the following changes :
    • Create a new property with name org.springframework.version and value 3.0.1.RELEASE
      • Create a new property with name maven.compiler.source and value according to the version of your Java runtime environment, we will use 1.6
        • Create a new property with name maven.compiler.target and value according to the version of your Java runtime environment, we will use 1.6
        1. Navigate to the „Dependencies“ page of the POM editor and create the following dependencies (you should fill the „GroupId“, „Artifact Id“ and „Version“ fields of the „Dependency Details“ section at that page) :
          • Group Id : org.springframework Artifact Id : spring-web Version : ${org.springframework.version}
            • Group Id : org.aspectj Artifact Id : aspectjrt Version : 1.6.7
            1. Navigate to the “Plugins” page of the POM editor and create the following plugin (you should fill the „GroupId“, „Artifact Id“ and „Version“ fields of the „Plugin Details“ section at that page) :
              • Group Id : org.codehaus.mojo Artifact Id : aspectj-maven-plugin Version : 1.3
              1. At the “Plugins” page of the POM editor, select the newly created plugin (from the “Plugins” section), and bind it to the compile execution goal. To do so, locate the “Execution” section and create a new execution. At the “Execution Details” section create a new goal and name it “compile
              2. The newly created plugin needs one final configuration change. We must define what version of Java runtime environment we are using in order for the AspectJ compiler to properly weave aspect classes. We need to edit the “pom.xml” file to perform the change. Select the “pom.xml” page of the POM editor, locate the newly created plugin and alter it as follows :
              3. <plugin>
                 <groupId>org.codehaus.mojo</groupId>
                 <artifactId>aspectj-maven-plugin</artifactId>
                 <version>1.3</version>
                 <configuration>
                  <source>${maven.compiler.source}</source>
                  <target>${maven.compiler.target}</target>
                 </configuration>
                 <executions>
                  <execution>
                   <goals>
                    <goal>compile</goal>
                   </goals>
                  </execution>
                 </executions>
                </plugin>
              4. Finally change the “maven-compiler-plugin” as shown below :
              5. <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>2.0.2</version>
                 <configuration>
                  <source>${maven.compiler.source}</source>
                  <target>${maven.compiler.target}</target>
                 </configuration>
                </plugin>
                

              As you can see Maven manages library dependencies declaratively. A local repository is created (by default under {user_home}/.m2 folder) and all required libraries are downloaded and placed there from public repositories. Furthermore intra – library dependencies are automatically resolved and manipulated.

              The next step is to provide hooks for the web application so as to load the Spring context upon startup.

              Locate the „web.xml“ file under /src/main/webapp/WEB-INF and add the following :

              For loading the Spring context upon startup,

              <listener>
               <listener-class>
                org.springframework.web.context.ContextLoaderListener
               </listener-class>
              </listener>
              

              Now lets create the applicationContext.xml file that will drive Spring container. Create the file under /src/main/webapp/WEB-INF directory. An example „applicationContext.xml“ is presented below

              <beans xmlns="http://www.springframework.org/schema/beans"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
               xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
               xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
               xmlns:task="http://www.springframework.org/schema/task"
               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
                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
                 http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
                 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                 http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">
              
               <context:component-scan base-package="com.javacodegeeks.aspectjspring" />
               
               <bean class="com.javacodegeeks.aspectjspring.aspects.GreetingAspect" factory-method="aspectOf">
                   <property name="message" value="Hello from Greeting Aspect"/>
               </bean>
              
              </beans>
              

              Things to notice here :

              1. Change the base-package attribute of the context:component-scan element to whatever is the base package of your project so as to be scanned for Spring components
              2. We have to define our aspects in “applicationContext.xml” only if we want to inject dependences to them
              3. AspectJ denotes the term of “aspect association”. It defines how to manage aspect state. The following state associations are supported:
                • Per JVM – one shared aspect instance is constructed and used (default)
                • Per object – aspect has its own state per every advised object
                • Per control flow – aspect has its own state per particular control flow
                  All AspectJ aspect classes have “hasAspect()” and “aspectOf()” static methods. These methods are implicitly generated by AspectJ compiler/load time weaver. So, for the default aspect state there is a single aspect instance that can be retrieved using the “aspectOf()” method

              Lets create now the “greeting” Spring service and the relevant “greeting” AspectJ aspect. Create a sub – package named “services” under your main package and place the “GreetingService” class there. An example “greeting” service is shown below :

              package com.javacodegeeks.aspectjspring.services;
              
              import org.springframework.stereotype.Service;
              
              @Service("greetingService")
              public class GreetingService {
              
               public String sayHello() {
                return "Hello from Greeting Service";
               }
               
              }
              

              Create a sub – package named “aspects” under your main package and place the “GreetingAspect” class there. An example “greeting” aspect is shown below :

              package com.javacodegeeks.aspectjspring.aspects;
              
              import org.aspectj.lang.ProceedingJoinPoint;
              import org.aspectj.lang.annotation.Around;
              import org.aspectj.lang.annotation.Aspect;
              
              @Aspect
              public class GreetingAspect {
              
               private String message;
              
               public void setMessage(String message) {
                this.message = message;
               }
              
               @Around("execution(* com.javacodegeeks.aspectjspring.services.GreetingService.*(..))")
               public Object advice(ProceedingJoinPoint pjp) throws Throwable {
                String serviceGreeting = (String) pjp.proceed();
                return message + " and " + serviceGreeting;
               }
               
              }
              

              Finally locate the main Web page of your project, “index.jsp”, under /src/main/webapp folder and alter it as follows :

              <%@ page language="java" import="org.springframework.web.context.WebApplicationContext, org.springframework.web.context.support.WebApplicationContextUtils, com.javacodegeeks.aspectjspring.services.GreetingService"%>
              <%@page contentType="text/html" pageEncoding="UTF-8"%>
              <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
                 "http://www.w3.org/TR/html4/loose.dtd">
              
              <% 
              WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
              GreetingService greetingService = (GreetingService) webApplicationContext.getBean("greetingService");
              %>
              <html>
                  <head>
                      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
                      <title>JSP Page</title>
                  </head>
                  <body>
                      <h1>Test service invoked and greets you by saying : <%=greetingService.sayHello()%></h1>
                  </body>
              </html>
              

              Things to notice here :

              1. Upon page load, we retrieve the Spring Web application context, and lookup our “greeting” service. All we have to do is to invoke the “sayHello()” method to see the combined greeting message from our aspect and the service

              To build the application right click on your project ? Run As ? Maven package

              To deploy the web application just copy the „.war“ file from the „target“ directory to Apache – Tomcat “webapps” folder

              To lunch the application point your browser to the following address

              http://localhost:8080/{application_name}/

              If all went well you should see your main web page displaying the following :

              “Test service invoked and greets you by saying : Hello from Greeting Aspect and Hello from Greeting Service”

              You can download the project from here

              Hope you liked it

              Justin

              Related Articles :

              Byron Kiourtzoglou

              Byron is a master software engineer working in the IT and Telecom domains. He is an applications developer in a wide variety of applications/services. He is currently acting as the team leader and technical architect for a proprietary service creation and integration platform for both the IT and Telecom industries in addition to a in-house big data real-time analytics solution. He is always fascinated by SOA, middleware services and mobile development. Byron is co-founder and Executive Editor at Java Code Geeks.
              Subscribe
              Notify of
              guest

              This site uses Akismet to reduce spam. Learn how your comment data is processed.

              5 Comments
              Oldest
              Newest Most Voted
              Inline Feedbacks
              View all comments
              Fernando Franzini
              Fernando Franzini
              11 years ago

              Heloo
              I’m using bean1 with @AfterReturning to make a proxy for a existing bean2 that implements an transactional processing, Bean2 is using @Transactional. The problem is the bean1 proxy method with @AfterReturning is running within a transaction that target bean1 and I would like to execute proxy method outside the target bean1 transaction.
              I already searched but did not find how to do this. Anyone know how to do it?
              Best Regards.

              Anurag
              Anurag
              10 years ago

              I am a newbie to AspectJ world.I tried executing you example but on Server StartUp it give me the below error:

              org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘com.javacodegeeks.aspectjspring.aspects.GreetingAspect#0’ defined in ServletContext resource [/WEB-INF/applicationContext.xml]: No matching factory method found: factory method ‘aspectOf’. Check that a method of the specified name exists and that it is static.

              Also please help me understand that with no aop.xml and Runtime Weaving Code will this example.

              Appreciate your help.

              Anurag
              Anurag
              10 years ago

              Hi,

              I am able to run the application by removing factory-method=”aspectOf” from applicationContext.
              But the aspect is not getting executed.

              Please help.

              Andre CS
              Andre CS
              10 years ago

              Hi,

              Great article!

              I’d recommend configuring variable “org.springframework.version” to use version “3.0.7.RELEASE” instead.

              See ya.

              Netha
              Netha
              9 years ago

              Hi,
              I need to invoke the pointcut in Aspect class for getter/setter methods in domain object to enrich the object.

              Can you please help me with sample code with annotations only without any configuration.

              Many thanks in advance.

              Back to top button